一、前言
这一节,我们将学习一下如何通过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信息,实现了分步查询的效果,且控制台打印结果正常。
=======欢迎大家拍砖,小手一抖,多多点赞哟!=======
版权声明:本文为博主原创文章,允许转载,但转载必须标明出处。