1.(多对一)关联映射
1.1.数据库映射关系介绍
多对一:
多个员工属于一个部门:单向的多对一关系,在Domain类中,在多方配置一个一方的属性。
数据库的表现:在多方有一个一方的外键。
一对多:
一个部门有多个员工:单向的一对多。在Domain中,在一方配置一个集合,集合的内容属性是多方。
数据库的表现:在多方有一个一方的外键。
多对多:
数据库使用中间表。Domain也是放一个集合属性。
一对一:
数据库的表现形式:类似于单向的多对一。
说明:现在基于多对一的情况,有用户和部门两个对象,一个部门有多个用户,这时需要从多方入手,即从用户方入手,查询一个用户,并得到用户所在的部门,就应该在用户所在的Domain类中增加一个部门Dept的字段。
1.2.多对一嵌套结果
创建对应多对一的Domain类:
Department类:
/** * 部门类:多对一情况,多个员工对应一个部门 */ public class Department { private Long id; private String dName; //部门名称 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getdName() { return dName; } public void setdName(String dName) { this.dName = dName; } @Override public String toString() { return "Department{" + "id=" + id + ", dName='" + dName + '\'' + '}'; } }
Employee类:
/** * 员工类:基于多对一的情况进行创建:多个员工对应一个部门 * 此时在多方有一个一方的属性 */ public class Employee { private Long id; private String name; //员工姓名 private String password; //密码 //单向的多对一 private Department dept; //部门 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Department getDept() { return dept; } public void setDept(Department dept) { this.dept = dept; } @Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + ", dept=" + dept + '}'; } }
Mapper层:
EmployeeMapper:
public interface EmployeeMapper { Employee queryOneById(Long id); }
EmployeeMapper.xml:
嵌套结果查询只需要发送一条Sql语句,使用左外连接left join去连接查询,再将查询到的结果Employee进行封装,注意相同列别名在column中的体现:
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="cn.yif.mybatis.manytoone.mapper.EmployeeMapper"> <resultMap id="manytooneMap" type="cn.yif.mybatis.manytoone.domain.Employee"> <result property="id" column="id">result> <result property="name" column="name">result> <result property="password" column="password">result> <association property="dept" javaType="cn.yif.mybatis.manytoone.domain.Department"> <result property="id" column="did">result> <result property="dName" column="dname">result> association> resultMap> <select id="queryOneById" parameterType="Long" resultMap="manytooneMap"> SELECT emp.id, emp.name, emp.password, dep.id did, dep.name dname FROM t_employee emp LEFT JOIN t_dept dep ON emp.dept_id = dep.id WHERE emp.id = #{id} select> mapper>
1.3.多对一嵌套查询
Domain类创建与多对一嵌套结果查询相同,此处略。
Mapper层:
EmployeeMapper:
public interface EmployeeMapper { Employee queryOneById(Long id); Department queryDeptById(Long id); }
EmployeeMapper.xml:
嵌套查询需要发送两条Sql,其中一条查询正常的t_employee中的数据列,另外一条查询到对应的t_dept中的数据列,使用select属性进行联接,将Domain中的dept对象进行返回映射,封装成需要的数据:
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="cn.yif.mybatis.manytoone.mapper2sql.EmployeeMapper"> <resultMap id="manytooneMap" type="cn.yif.mybatis.manytoone.domain.Employee"> <result property="id" column="id">result> <result property="name" column="name">result> <result property="password" column="password">result> <association property="dept" column="dept_id" select="queryDeptById"> association> resultMap> <select id="queryOneById" parameterType="Long" resultMap="manytooneMap"> select id, name, password, dept_id from t_employee where id = #{id} select> <select id="queryDeptById" parameterType="Long" resultType="cn.yif.mybatis.manytoone.domain.Department"> select id, name dName from t_dept where id = #{id} select> mapper>
2.(一对多)集合映射
2.1.数据库映射关系介绍
最常见的是员工和部门的关系:在部门方需要查询某一个部门下的所有员工。部门与员工之间的关系是一对多的关系。
基于多对一的关联查询的数据库表,一对多关注的重点是部门方,在部门一方中应该有一个多方员工的集合属性,用于与员工方进行关联,而数据库中的表现则是多方有一个一方的外键属性。
2.2.一对多嵌套结果
一对多关注的对象是部门,在部门Domain中有一个集合属性的员工对象;
Department类:
/** * 部门类:一对多情况,一个部门对应多个员工 */ public class Department { private Long id; private String dName; //部门名称 private ListemployeeList; //一对多,在部门中有一个集合类型的员工属性 }
Employee类:
/** * 一对多情况,一个部门对应多个员工,关注点在部门方 */ public class Employee { private Long id; private String name; //员工姓名 private String password; //密码 }
对应DepartmentMapper接口:
public interface DepartmentMapper { /** * 查询一个部门下的所有员工 * @param id * @return */ Department queryOneDeptById(Long id); }
对应DepartmentMapper.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="cn.yif.mybatis.onetomany.mapper.DepartmentMapper"> <resultMap id="onetomanyMap" type="cn.yif.mybatis.onetomany.domain.Department"> <result property="id" column="dId">result> <result property="dName" column="dName">result> <collection property="employeeList" ofType="cn.yif.mybatis.onetomany.domain.Employee"> <result property="id" column="id">result> <result property="name" column="name">result> <result property="password" column="password">result> collection> resultMap> <select id="queryOneDeptById" parameterType="Long" resultMap="onetomanyMap"> select dept.id dId, dept.name dName, emp.id, emp.name, emp.password, emp.dept_id from t_dept dept left join t_employee emp on dept.id = emp.dept_id where dept.id = #{id} select> mapper>
2.3.一对多嵌套查询
对应Domain层与一对多前台结果是一样的。
对应DepartmentMapper接口:
public interface DepartmentMapper { /** * 查询一个部门下的所有员工 * @param id * @return */ Department queryOneDeptById(Long id); ListqueryAllEmployee(); }
对应DepartmentMapper.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="cn.yif.mybatis.onetomany.mapper2sql.DepartmentMapper"> <resultMap id="onetomanyMap" type="cn.yif.mybatis.onetomany.domain.Department"> <result property="id" column="id">result> <result property="name" column="name">result> <association property="employeeList" column="dept_id" select="queryAllEmployee"/> resultMap> <select id="queryOneDeptById" parameterType="Long" resultMap="onetomanyMap"> select id, name from t_dept where id = #{id} select> <select id="queryAllEmployee"> select id, name, password, dept_id from t_employee select> mapper>
3.MyBatis缓存
3.1.SqlSession一级缓存
MyBastis中默认开启的一级缓存SqlSession,缓存对象存储周期为第一次获取,到SqlSession对象被销毁,或者是SqlSession.clearCache()调用的时候。作用是使用到同一个SqlSession获取查询语句的时候,不会下发多个查询语句,具体示例如下:
在EmployeeMapper接口中配置了查询所有的员工接口:
public interface EmployeeMapper { ListqueryAll(); }
对应Mapper.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="cn.yif.mybatis.cache.mapper.EmployeeMapper"> <resultMap id="queryAllMap" type="cn.yif.mybatis.manytoone.domain.Employee"> <result property="id" column="id">result> <result property="name" column="name">result> <result property="password" column="password">result> <association property="dept" javaType="cn.yif.mybatis.manytoone.domain.Department"> <result property="id" column="dId">result> <result property="dName" column="dName">result> association> resultMap> <select id="queryAll" resultMap="queryAllMap"> select emp.id, emp.name, emp.password, emp.dept_id, dept.id dId, dept.name dName from t_employee emp left join t_dept dept on emp.dept_id = dept.id select> mapper>
编写对应测试类测试SqlSession一级缓存:
public class EmployeeMapperTest { @Test public void testCache(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class); Listlist = mapper.queryAll(); System.out.println(list); System.out.println(list.size()); System.out.println("===========华丽分割线============"); sqlSession.getMapper(EmployeeMapper.class); list = mapper.queryAll(); System.out.println(list.size()); } }
可以看到测试结果如下:
3.2.SqlSessionFactory二级缓存
MyBatis的二级缓存是SqlSessionFactory级别缓存,缓存对象存储周期为第一次获取,到SqlSessionFactory被销毁为止。
注意:
- 默认情况下,只开启一级缓存SqlSession,如果需要开启MyBatis二级缓存,需要我们在对应的Mapper.xml中添加一个
标签,开启二级缓存。 - 对应的Domain对象,实现java.io.Serializable接口。