Mybatis多表关联查询与动态SQL
一、多表关联查询
表与表之间有三种常见的关联关系,分别是一对一,一对多与多对多关系,MyBatis直接提供一对一与一对多的关联关系,可以通过间接的方式实现多对多关联。
1.1、一对一关系
1.1.1、执行环境
1.1.2、关联查询(1次查询
实体:
用户:
/**用户POJO*/ public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
员工:
/**员工POJO*/ public class Emp { private int id; /**用户编号*/ private int user_id; private String realname; private String email; /**用户对象*/ private User user; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getUser_id() { return user_id; } public void setUser_id(int user_id) { this.user_id = user_id; } public String getRealname() { return realname; } public void setRealname(String realname) { this.realname = realname; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public User getUser() { return user; } public Emp setUser(User user) { this.user = user; return this; } }
接口:
import com.zhangguo.mybatis03.entities.Emp; /**员工数据访口*/ public interface EmpMapper { /**获得员工通过员工编号*/ Emp getEmpById_1(int id); }
映射:
<?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.zhangguo.mybatis03.dao.EmpMapper"> <!--一对一查询,方法1,通过内联接--> <select id="getEmpById_1" resultMap="empMap_1" parameterType="int"> SELECT emp.id, emp.user_id, emp.realname, emp.email, `user`.username, `user`.`password` FROM emp INNER JOIN `user` ON emp.user_id = `user`.id where emp.id=#{id} </select> <!--员工关联查询结果映射--> <resultMap id="empMap_1" type="Emp"> <id property="id" column="id"></id> <result property="user_id" column="user_id"></result> <result property="realname" column="realname"></result> <result property="email" column="email"></result> <!--映射关系,指定属性与属性的类型--> <association property="user" javaType="User"> <id property="id" column="user_id"></id> <result property="username" column="username"></result> <result property="password" column="password"></result> </association> </resultMap> </mapper>
测试:
import com.zhangguo.mybatis03.entities.Emp; import org.junit.Assert; import org.junit.Test; import org.junit.Before; import org.junit.After; /** * EmpDao Tester. * * @author <Authors name> * @version 1.0 * @since <pre>09/30/2018</pre> */ public class EmpDaoTest { EmpMapper empDao; @Before public void before() throws Exception { empDao=new EmpDao(); } @After public void after() throws Exception { } /** * Method: getEmpById_1(int id) * 获得员工通过员工编号 */ @Test public void testGetEmpById_1() throws Exception { Emp entity=empDao.getEmpById_1(1); System.out.println(entity); Assert.assertNotNull(entity); } }
1.1.3、嵌套查询(2次查询)
实体:同上
接口:
/**获得员工通过员工编号,多次查询*/ Emp getEmpById_2(int id);
映射:
<!--一对一查询,方法2,通过多次查询(嵌套查询)--> <select id="getEmpById_2" resultMap="empMap_2"> SELECT emp.id, emp.user_id, emp.realname, emp.email FROM emp where id=#{id} </select> <!--员工多次查询结果映射--> <resultMap id="empMap_2" type="Emp"> <id property="id" column="id"></id> <result property="user_id" column="user_id"></result> <result property="realname" column="realname"></result> <result property="email" column="email"></result> <!--通过外键user_id再次发起查询,调用selectUserById获得User对象--> <association property="user" column="user_id" select="selectUserById"></association> </resultMap> <!--根据用户编号获得用户对象--> <select id="selectUserById" resultType="User"> SELECT `user`.id, `user`.username, `user`.`password` FROM `user` where id=#{id} </select>
测试:
/** * Method: getEmpById_2(int id) * 获得员工通过员工编号,一对一方法二 */ @Test public void testGetEmpById_2() throws Exception { Emp entity=empDao.getEmpById_2(2); System.out.println(entity); Assert.assertNotNull(entity); }
学习总结
MyBatis中使用association标签来解决一对一的关联查询,association标签可用的属性如下:
- property:对象属性的名称
- javaType:对象属性的类型
- column:所对应的外键字段名称
- select:使用另一个查询封装的结果
1.2、一对多关系
1.2.1、执行环境
1.2.2、关联查询(1次查询)
实体:
员工:
/**员工POJO*/ public class Emp { private int id; /**用户编号*/ private int user_id; private String realname; private String email; /**用户对象*/ private User user; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getUser_id() { return user_id; } public void setUser_id(int user_id) { this.user_id = user_id; } public String getRealname() { return realname; } public void setRealname(String realname) { this.realname = realname; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public User getUser() { return user; } public Emp setUser(User user) { this.user = user; return this; } @Override public String toString() { return "Emp{" + "id=" + id + ", user_id=" + user_id + ", realname='" + realname + '\'' + ", email='" + email + '\'' + ", user=" + user + '}'; } }
用户:
import java.util.List; /**用户POJO*/ public class User { private int id; private String username; private String password; /**员工集合,一个用户对象对应多个员工对象*/ private List<Emp> emps; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<Emp> getEmps() { return emps; } public User setEmps(List<Emp> emps) { this.emps = emps; return this; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", emps=" + emps + '}'; } }
接口:
/**获得用户通过用户编号,1对多级联查询*/ User getUserById_1(int id);
映射:
<!--一对多查询,方法1,通过内联接--> <select id="getUserById_1" resultMap="userMap_1" parameterType="int"> SELECT emp.id, emp.user_id, emp.realname, emp.email, `user`.username, `user`.`password` FROM emp INNER JOIN `user` ON emp.user_id = `user`.id where `user`.id=#{id} </select> <resultMap id="userMap_1" type="User"> <id property="id" column="user_id"></id> <result property="username" column="username"></result> <result property="password" column="password"></result> <!--将emps对象映射成一个集合,emps是user类型中的属性,ofType用于指定集合中存放的对象类型--> <collection property="emps" ofType="Emp"> <id property="id" column="id"></id> <result property="user_id" column="user_id"></result> <result property="realname" column="realname"></result> <result property="email" column="email"></result> </collection> </resultMap> 测试: /** * Method: getUserById_1(int id) * 获得用户过用户编号,级联查询 */
@Test public void testGetUserById_1() throws Exception { User entity=empDao.getUserById_1(2); System.out.println(entity); Assert.assertNotNull(entity); }
映射:
<resultMap id="userMap_1" type="User"> <id property="id" column="user_id"></id> <result property="username" column="username"></result> <result property="password" column="password"></result> <!--将emps对象映射成一个集合,emps是user类型中的属性,ofType用于指定集合中存放的对象类型--> <collection property="emps" ofType="Emp"> <id property="id" column="id"></id> <result property="user_id" column="user_id"></result> <result property="realname" column="realname"></result> <result property="email" column="email"></result> <!--映射关系,指定属性与属性的类型--> <association property="user" javaType="User"> <id property="id" column="user_id"></id> <result property="username" column="username"></result> <result property="password" column="password"></result> </association> </collection> </resultMap>
1.1.3、嵌套查询(多次查询)
实体:同上
接口:
/**获得用户通过用户编号,1对多嵌套查询*/ User getUserById_2(int id);
映射:
<!--一对多查询,方法2,通过嵌套查询多次--> <select id="getUserById_2" resultMap="userMap_2" parameterType="int"> SELECT `user`.id, `user`.username, `user`.`password` FROM `user` where id=#{id} </select> <resultMap id="userMap_2" type="User"> <id property="id" column="user_id"></id> <result property="username" column="username"></result> <result property="password" column="password"></result> <!--将emps对象映射成一个集合,emps是user类型中的属性,ofType用于指定集合中存放的对象类型--> <!--select用于指定再次查询的SQL编号,column用于指定参数列--> <collection property="emps" ofType="Emp" column="id" select="selectEmpById"></collection> </resultMap> <!--根据员工编号获得员工对象--> <select id="selectEmpById" resultType="Emp"> SELECT emp.id, emp.user_id, emp.realname, emp.email FROM emp where user_id=#{id} </select>
测试:
/** * Method: getUserById_2(int id) * 获得用户过用户编号,嵌套查询 */ @Test public void testGetUserById_2() throws Exception { User entity=empDao.getUserById_2(5); System.out.println(entity); Assert.assertNotNull(entity); }
学习总结:
MyBatis中使用collection标签来解决一对多的关联查询,ofType属性指定集合中元素的对象类型。
Mybatis多表关联查询与动态SQL(下):https://developer.aliyun.com/article/1509370