自动映射、手动映射、懒加载、缓存
1. 自动映射与手动映射
mybatis是自动将查询结果中的数据封装进对象或对象集合,但前提条件是对象或对象集合中属性名与查询结果一致
所以当需要将查询结果封装进属性名不一致的对象或对象集合时就需要手动映射
下图为查询字段名称
下图为实体类Emp属性名称
下图为实体类EmpName的属性名称
1.1 自动映射配置文件
<?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.khue.mapper.EmpNameMapper">
<resultMap id="getEmpName" type="empname">
<id property="id" column="empno"/>
<result property="name" column="ename"/>
<result property="work" column="job"/>
<result property="boss" column="mgr"/>
<result property="date" column="hiredate"/>
<result property="pay" column="sal"/>
<result property="add" column="comm"/>
<result property="part" column="deptno"/>
</resultMap>
<select id="getEmpByEmpno" resultMap="getEmpName">
select * from emp
where empno=#{empno}
</select>
</mapper>
1.2 手动映射配置文件
手动映射需使用标签
标签用于主键约束的字段
标签用于其它字段
<?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.khue.mapper.EmpNameMapper">
<resultMap id="getEmpName" type="empname">
<id property="id" column="empno"/>
<result property="name" column="ename"/>
<result property="work" column="job"/>
<result property="boss" column="mgr"/>
<result property="date" column="hiredate"/>
<result property="pay" column="sal"/>
<result property="add" column="comm"/>
<result property="part" column="deptno"/>
</resultMap>
<select id="getEmpByEmpNameid" resultMap="getEmpName">
select * from emp
where empno=#{id}
</select>
</mapper>
1.3 打印结果
2. 多表关联查询
2.1 一对一映射
一个员工对应一个部门,员工表与部门表是两张表,根据员工编号查询出该员工的所属部门,就需要一对一的映射关系
一对一映射配置文件
<?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.khue.mapper.EmpJoinDeptMapper">
<resultMap id="getEmp" type="empjoindept">
<id property="empno" column="empno"/>
<result property="ename" column="ename"/>
<result property="job" column="job"/>
<result property="mgr" column="mgr"/>
<result property="hiredate" column="hiredate"/>
<result property="sal" column="sal"/>
<result property="comm" column="comm"/>
<result property="deptno" column="deptno"/>
<association property="dept" javaType="dept">
<id property="deptno" column="deptno"/>
<result property="dname" column="dname"/>
<result property="loc" column="loc"/>
</association>
</resultMap>
<select id="getEmpJoinDept" resultMap="getEmp">
select *
from emp left outer join dept on emp.deptno=dept.deptno
where empno=#{empno}
</select>
</mapper>
打印结果
2.2 一对多映射
一个部门可以有多个员工,给定一个部门号,查询给部门的所有员工,就需要一对多的映射关系
一对多映射配置文件
<?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.khue.mapper.DeptJoinEmpMapper">
<resultMap id="getDept" type="DeptJoinEmp">
<id property="deptno" column="deptno"/>
<result property="dname" column="dname"/>
<result property="loc" column="loc"/>
<collection property="emp" ofType="emp">
<id property="empno" column="empno"/>
<result property="ename" column="ename"/>
<result property="job" column="job"/>
<result property="mgr" column="mgr"/>
<result property="hiredate" column="hiredate"/>
<result property="sal" column="sal"/>
<result property="comm" column="comm"/>
<result property="deptno" column="deptno"/>
</collection>
</resultMap>
<select id="getDeptJoinEmp" resultMap="getDept">
select *
from dept left outer join emp on dept.deptno=emp.deptno
where dept.deptno=#{deptno}
</select>
</mapper>
打印结果
2.3 多对多映射
一个员工可以参与多个项目,一个项目也可以由多个员工参与,给定一个员工编号,查询该员工参与的项目,这就需要多对多的映射关系
其实多对多映射关系可以拆分成一个一对多加一个一对一的映射关系
即:一个员工可以对应多个项目编号,但一个项目编号只能对应一个项目
多对多映射配置文件
<?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.khue.mapper.EmpJoinTaskListMapper">
<resultMap id="getEmp" type="empjointasklist">
<id property="empno" column="empno"/>
<result property="ename" column="ename"/>
<result property="job" column="job"/>
<result property="mgr" column="mgr"/>
<result property="hiredate" column="hiredate"/>
<result property="sal" column="sal"/>
<result property="comm" column="comm"/>
<result property="deptno" column="deptno"/>
<collection property="list" ofType="tasklistjoinprojects">
<id property="empno" column="empno"/>
<id property="pid" column="pid"/>
<association property="projects" javaType="projects">
<id property="pid" column="pid"/>
<result property="pname" column="pname"/>
</association>
</collection>
</resultMap>
<select id="getEmp" resultMap="getEmp">
select *
from emp left outer join tasklist on emp.empno=tasklist.empno left outer join projects on tasklist.pid=projects.pid
where emp.empno=#{empno}
</select>
</mapper>
打印结果
3. 懒加载
懒加载也叫懒查询
指在查询多个关联表时,如果当前只需要一个表的信息,那么只执行当前表的查询语句,而相关联的表等到需要调用其信息时才执行查询的一种优化机制
懒加载只是在时间轴上将运算分散,可以降低单位时间内数据库的运算压力和预算量,但不能降低运算总量
3.1 启动懒加载
在核心配置文件中的标签开启
在启动懒加载的同时,需要先关闭积极加载
积极加载是指无论当前获取的是
<?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="jdbc.properties">
</properties>
<settings>
<setting name="logImpl" value="LOG4J"/>
<!-- 开启懒加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭积极加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<typeAliases>
<package name="cn.khue.beans"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="cn.khue.mapper"/>
</mappers>
</configuration>
4. 缓存
4.1 一级缓存
指在同一个sqlSession中执行多次相同的SQL语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),之后会从缓存中获取数据,而不再从数据库查询的一种优化机制
开启:默认自动开启
缺点:如果数据库发生改变,而此时并没有从数据库获取最新数据,则会造成脏读
解决:使用sqlSession.clearCache()或sqlSession.commit()或sqlSession.close()清除缓存
4.2 二级缓存
指在同一个factory.build()中执行多次相同的SQL语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),之后会从缓存中获取数据,而不再从数据库查询的一种优化机制
开启:
第一步:在核心配置文件中使用标签开启name=“cacheEnabled” value=“true”
第二步:在mapper映射配置文件中使用
第三步:在需要执行的SQL语句处使用useCache=“true” flushCache="false"开启
第四步:使用的实体类(POJO对象)需要实现java.io.Serializable接口
缺点:相比一级缓存更容易造成数据脏读
解决:谨慎使用
4.3 mapper映射配置文件中的参数
<cache eviction="" flushInterval="" size="" readOnly=""/>
eviction表示回收策略
- LRU 最近最少使用的:移除最长时间不被使用的对象(默认策略)
- FIFO 先进先出:按对象进入缓存的顺序来移除它们
- SOFT 软引用:移除基于垃圾回收器状态和软引用规则的对象
- WEAK 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInterval 表示刷新间隔时间(默认不设置)
size 表示引用数目(默认为1024)
readOnly 表示只读属性(默认false)