老司机学习MyBatis之如何使用association解决一对一关联查询

一、前言

这一节,我们将学习一下如何通过MyBatis提供的association关键字来实现关联查询,主要是实现一对一关联查询。有两种实现方式,分别是嵌套查询和分段查询

二、案例

完整的工程目录如下:


在MySQL数据库新建两张数据库表t_user和t_role,并插入若干条数据

CREATE TABLE t_user (
  id int(10) NOT NULL AUTO_INCREMENT,
  loginId varchar(20) DEFAULT NULL,
  userName varchar(100) DEFAULT NULL,
  roleId int(10),
  note varchar(255) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

INSERT INTO t_user(loginId,userName,roleId,note) VALUES ('queen', '奎恩', 1, '专门负责提鞋的。。。');
INSERT INTO t_user(loginId,userName,roleId,note) VALUES ('king', '金狮子', 2, '磁性果实能力');
INSERT INTO t_user(loginId,userName,roleId,note) VALUES ('Lucy', '路西', 3, '打败多弗朗明哥。。。');
=========================================================
CREATE TABLE t_role (
  id int(10) NOT NULL AUTO_INCREMENT,
  roleName varchar(20) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

INSERT INTO t_role(roleName) VALUES ('自定义角色');
INSERT INTO t_role(roleName) VALUES ('前海贼');
INSERT INTO t_role(roleName) VALUES ('未来海贼王');

User实体类

public class User {
	// ID,唯一性
	private int id;
	// 登录ID
	private String loginId;
	// 用户名
	private String userName;
	// 角色
	private Role role;
	// 备注
	private String note;

        public User(){
 
        }
         
	public User(int id, String loginId, String userName, Role role, String note) {
		this.id = id;
		this.loginId = loginId;
		this.userName = userName;
		this.role = role;
		this.note = note;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLoginId() {
		return loginId;
	}

	public void setLoginId(String loginId) {
		this.loginId = loginId;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}

	public String getNote() {
		return note;
	}

	public void setNote(String note) {
		this.note = note;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", loginId=" + loginId + ", userName="
				+ userName + ", role=" + role + ", note=" + note + "]";
	}

}

Role实体类

public class Role {
	private int id;
	private String roleName;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getRoleName() {
		return roleName;
	}

	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}

        public Role(){
 
        }
        
	public Role(int id, String roleName) {
		this.id = id;
		this.roleName = roleName;
	}

	@Override
	public String toString() {
		return "Role [id=" + id + ", roleName=" + roleName + "]";
	}

}

配置文件log4j.properties

log4j.rootLogger=DEBUG,A1
log4j.logger.com.queen = DEBUG
log4j.logger.org.mybatis = DEBUG

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

配置文件db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root

配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<properties resource="db.properties"></properties>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="UserMapper.xml" />
	</mappers>
</configuration>

新建接口类UserMapper.java,增加接口方法getUserById

public interface UserMapper {
	
	/**
	 * 根据ID查询User信息,返回一条记录User
	 * @param id
	 * @return
	 */
	public User getUserById(int id);
	
}

UserMapper.xml文件配置,嵌套查询

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.queen.mybatis.mapper.UserMapper">

	<resultMap type="com.queen.mybatis.bean.User" id="userResultMap">
		<id property="id" column="id"/>
	    <result property="loginId" column="loginId" />
	    <result property="userName" column="userName"/>
	    <result property="note" column="note"/>
            <!--assocication可以指定联合的JavaBean对象 
                property="role"指定哪个属性是联合的对象
                javaType:指定这个属性对象的类型
            -->
	    <association property="role" javaType="com.queen.mybatis.bean.Role">
	    	<id column="role_id" property="id"/>
	    	<result column="roleName" property="roleName"/>
	    </association>
	</resultMap>
	
	<select id="getUserById" resultMap="userResultMap">
		select m.id id, m.loginId loginId, m.userName userName, m.roleId roleId,m.note note, n.id role_id, n.roleName roleName 
			from t_user m left join t_role n on m.roleId=n.id
			where m.id=#{id}
	</select>
	
</mapper>

新增测试类MyBatisTest,添加测试方法testGetUserByAssocication

@Test
public void testGetUserByAssocication() throws IOException {
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try {
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		User user = mapper.getUserById(1);
		System.out.println(user);
		System.out.println(user.getRole());
	} finally {
		openSession.close();
	}
}

控制台打印结果如下:

2017-08-08 22:46:52,470 [main] [com.queen.mybatis.mapper.UserMapper.getUserById]-[DEBUG] ==>  Preparing: select m.id id, m.loginId loginId, m.userName userName, m.roleId roleId,m.note note, n.id role_id, n.roleName roleName from t_user m left join t_role n on m.roleId=n.id where m.id=? 
2017-08-08 22:46:52,558 [main] [com.queen.mybatis.mapper.UserMapper.getUserById]-[DEBUG] ==> Parameters: 1(Integer)
2017-08-08 22:46:52,597 [main] [com.queen.mybatis.mapper.UserMapper.getUserById]-[DEBUG] <==      Total: 1
User [id=1, loginId=queen, userName=奎恩, role=Role [id=1, roleName=自定义角色], note=专门负责提鞋的。。。]
Role [id=1, roleName=自定义角色]

这样我们可以通过association也能够实现关联属性的查询,使用association定义关联的单个对象的封装结果。

接下来我们介绍第二种:使用association进行分步查询,那么分步查询是什么意思呢?用我们上述例子,即我们查完User表数据后,我们在查询Role表数据。分多条SQL执行。

新建一个接口类RoleMapper,新增接口方法getRoleById

public interface RoleMapper {
	/**
	 * 根据ID查询Role信息,返回一条记录Role
	 * @param id
	 * @return
	 */
	public Role getRoleById(int id);
}

新建一个RoleMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.queen.mybatis.mapper.RoleMapper">
	<select id="getRoleById" resultType="com.queen.mybatis.bean.Role">
		select id, roleName from t_role where id=#{id}
	</select>
</mapper>

修改UserMapper文件,新增一个方法getUserByIdStep

/**
 * 根据ID查询User信息,返回一条记录User,分步查询
 * @param id
 * @return
 */
public User getUserByIdStep(int id);

修改UserMapper.xml文件,增加如下配置

<resultMap type="com.queen.mybatis.bean.User" id="userResultMapStep">
	<id property="id" column="id"/>
	<result property="loginId" column="loginId" />
	<result property="userName" column="userName"/>
	<result property="note" column="note"/>
	<!-- association定义关联对象的封装规则 
	    select:表明当前属性是调用select指定的方法查询出结果
	    column:指定将那一列的值传递给这个方法
	    整个流程:使用Select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
	 -->
	<association property="role" select="com.queen.mybatis.mapper.RoleMapper.getRoleById"
	    	column="roleId">
	</association>
</resultMap>
<select id="getUserByIdStep" resultMap="userResultMapStep">
	select * from t_user where id=#{id}
</select>

修改测试类MyBatisTest,添加测试方法testGetUserByAssocicationStep

@Test
public void testGetUserByAssocicationStep() throws IOException {
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try {
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		User user = mapper.getUserByIdStep(1);
		System.out.println(user);
		System.out.println(user.getRole());
	} finally {
		openSession.close();
	}
}

控制台打印结果如下:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.queen.mybatis.mapper.RoleMapper.getRoleById
### The error may exist in UserMapper.xml
### The error may involve com.queen.mybatis.mapper.UserMapper.getUserByIdStep
### The error occurred while handling results
### SQL: select * from t_user where id=?
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.queen.mybatis.mapper.RoleMapper.getRoleById
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:111)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:66)

结果事与愿违,报错了,这是为什么呢?注意我们一定要将新增的RoleMapper.xml映射文件配置到mybatis-config.xml文件中,配置如下:

<mappers>
	<mapper resource="UserMapper.xml" />
	<mapper resource="RoleMapper.xml" />
</mappers>

重新测试一下

2017-08-08 23:26:04,799 [main] [com.queen.mybatis.mapper.UserMapper.getUserByIdStep]-[DEBUG] ==>  Preparing: select * from t_user where id=? 
2017-08-08 23:26:04,853 [main] [com.queen.mybatis.mapper.UserMapper.getUserByIdStep]-[DEBUG] ==> Parameters: 1(Integer)
2017-08-08 23:26:04,909 [main] [com.queen.mybatis.mapper.RoleMapper.getRoleById]-[DEBUG] ====>  Preparing: select id, roleName from t_role where id=? 
2017-08-08 23:26:04,909 [main] [com.queen.mybatis.mapper.RoleMapper.getRoleById]-[DEBUG] ====> Parameters: 1(Integer)
2017-08-08 23:26:04,911 [main] [com.queen.mybatis.mapper.RoleMapper.getRoleById]-[DEBUG] <====      Total: 1
2017-08-08 23:26:04,911 [main] [com.queen.mybatis.mapper.UserMapper.getUserByIdStep]-[DEBUG] <==      Total: 1
User [id=1, loginId=queen, userName=奎恩, role=Role [id=1, roleName=自定义角色], note=专门负责提鞋的。。。]
Role [id=1, roleName=自定义角色]

从上述打印结果,可以看到控制台打印了两段SQL语句,一句用来查询User信息,另外一句用来查询Role信息,实现了分步查询的效果,且控制台打印结果正常。


=======欢迎大家拍砖,小手一抖,多多点赞哟!=======

版权声明:本文为博主原创文章,允许转载,但转载必须标明出处。


猜你喜欢

转载自blog.csdn.net/gaomb_1990/article/details/80638190