MyBatis中的自动映射
mybatis自动将查询结果中的数据封装进 对象或者对象集合
执行原理是什么? 相当于之前写的baseQuery方法 但是略有不同
图解
根据结果的字段名 >>> 找到类的set 方法 通过set方法给对象属性赋值
Mybatis手动映射
如果实体类中的属性名和数据库中的字段名不一样怎么办?
通过手动设定结果和实体类之间 的 映射关系解决
准备一个类名和数据库表格名 属性名和结果字段名有差异的实体类
接口
import com.bjsxt.entity.Dept; import com.bjsxt.entity.Employee; public interface DeptMapper { Dept getDeptJionEmpsDeptno(int deptno); }
映射文件
<?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.bjsxt.mapper.EmpMapper"> <!-- 当字段和属性不同, 可以通过别名的形式让其对应 但是不推荐 --> <!--<select id="findAllEmployee" resultType="employee"> select empno id,ename name ,job,mgr,hiredate,sal,comm,deptno from emp </select>--> <sql id="baseEmpSelect"> select empno ,ename ,job,mgr,hiredate,sal,comm,deptno from emp </sql> <!--推荐使用resultMap配置映射关系 可以简写 而且在其他功能下也可以使用 id 代表映射关系编号 type 代表映射关系对应java中的类 可以使用别名 --> <resultMap id="empMapping" type="employee"> <!--一般主键列使用id标签体现映射 关系--> <id property="id" column="empno"/> <!--一般非主键列 使用result标签体现映射关系--> <result property="name" 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"/> --> </resultMap> <!--在语句 标签中 使用resultMap 替换resultMap 自动映射和手动映射可以结合使用 二者并不矛盾 --> <select id="findAllEmployee" resultMap="empMapping"> <include refid="baseEmpSelect"/> </select> </mapper>
测试代码
public class Test { public static void main(String[] args) { SqlSession sqlSession = TestUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Employee allEmployee = mapper.findAllEmployee(7900); System.out.println(allEmployee); sqlSession.close(); }
多表关联查询
- 一对一
一对一 一个员工只能属于一个部门
一对多 一个部门可以拥有多个员工
多对多 被转换为两个一对多 其实还是一对多
在java 中通过组合 关系体现一对一和一对多的关系<-- 映射文件-->
<?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.bjsxt.mapper.EmpMapper2"> <!--通过映射resultMap体现 emp和dept之间的关系--> <resultMap id="emp2JoinDept" type="emp2"> <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"></id> <result property="dname" column="dname"></result> <result property="loc" column="loc"></result> </association> </resultMap> <select id="getEmp2JoinDeptnoByEmpno" resultMap="emp2JoinDept"> select * from emp e ,dept d where e.deptno=d.deptno and e.empno= #{empno} </select> </mapper> - 一对多
<-- 映射文件-->
<?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.bjsxt.mapper.EmpMapper2"> <!--通过映射resultMap体现 emp和dept之间的关系--> <resultMap id="emp2JoinDept" type="emp2"> <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"></id> <result property="dname" column="dname"></result> <result property="loc" column="loc"></result> </association> </resultMap> <select id="getEmp2JoinDeptnoByEmpno" resultMap="emp2JoinDept"> select * from emp e ,dept d where e.deptno=d.deptno and e.empno= #{empno} </select> <resultMap id="detpJoinEmps" type="dept"> <id property="deptno" column="deptno"></id> <result property="dname" column="dname"></result> <result property="loc" column="loc"></result> <collection property="emps" 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="getDeptJoinEmpsByDeptno" resultMap="detpJoinEmps"> select * from dept d left outer join emp e on d.deptno =e.deptno where d.deptno =#{deptno} </select> </mapper>
- 多对多
<-- 映射文件--> <?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.bjsxt.mapper.EmpMapper3"> <!--通过映射resultMap体现 emp和dept之间的关系--> <resultMap id="empJoinProjects" type="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 property="taskLists" ofType="taskList"> <id property="empno" column="empno"></id> <id property="pid" column="pid"></id> <association property="project" javaType="projects"> <id property="pid" column="pid"></id> <result property="pname" column="pname"></result> </association> </collection> </resultMap> <select id="getEmpWithProjects" resultMap="empJoinProjects"> select * from emp e left outer join taskList t on e.empno = t.empno left outer join projects p on t.pid = p.pid where e.empno =#{empno} </select> </mapper>
懒加载
或者叫懒查询 在查询时 一个结果对象的属性可能是集合
懒加载就是在获得当前对象时,先不去查询集合
当获得集合中中信息时, 再去查询
可以降低单位时间内 数据库的运算压力和预算量
但是不能降低运算总量 只是在时间轴上将运算的处理 分散开而已<settings> <setting name="logImpl" value="LOG4J"/> <!-- 开启延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 关闭积极加载 --> <setting name="aggressiveLazyLoading" value="false"/> </settings> 在mybatis中
mybatis中的缓存
一级缓存
Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
package com.bjsxt.testDemo; import com.bjsxt.entity.Projects; import com.bjsxt.mapper.ProjectsMapper; import org.apache.ibatis.session.SqlSession; public class Test5 { public static void main(String[] args) { SqlSession sqlSession = TestUtil.getSqlSession(); ProjectsMapper mapper = sqlSession.getMapper(ProjectsMapper.class); Projects projectsByPid = mapper.getProjectsByPid(1); System.out.println(projectsByPid); /*提交动作 会默认清空缓存*/ /* sqlSession.commit();*/ /*如果没有 提交动作 可以手动清空缓存*/ /*sqlSession.clearCache();*/ projectsByPid = mapper.getProjectsByPid(1); System.out.println(projectsByPid); sqlSession.close(); } }
二级缓存
二级缓存是多个sqlSession 对象共享的 前提是 多个SQLSession对象获得的mapper是同一个接口下的
二级缓存的划分依据是 namespace 每个namespace都会有自己独立的缓存区
所以二级缓存也叫作mapper级别的缓存
<?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.bjsxt.mapper.ProjectsMapper"> <cache /> <!-- useCache="true" 使用缓存 意为该sql语句执行时是要使用二级缓存的 默认值为true 如果改为false 那么意为者该语句禁用了二级缓存 flushCache="false" 代表取消刷新 缓存动作 意为每次执行该语句都不会刷新缓存 默认值为false 如果设置为true 那么每次执行都会刷新缓存 --> <select id="getProjectsByPid" resultType="projects" useCache="true" flushCache="false" > select * from projects where pid = #{pid} </select> </mapper>
<cache/>参数
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
如下例子:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
1. LRU – 最近最少使用的:移除最长时间不被使用的对象。
2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
mybatis中注解
public interface EmpMapper { @Select("select * from emp") @ResultType(Emp.class) List<Emp> findAll(); @Select("select * from emp where empno = #{empno}") Emp findEmpByEmpno(int empno); @Insert("insert into emp(ename,job) values(#{ename},#{job})") int addEmp(Emp emp); @Delete("delete from emp where empno = #{empno}") int removeEmp(int empno); @Update("update emp set ename = #{ename} where empno =#{empno}") int updateEmp(Emp emp); }
注解为了什么而存在
简化配置文件的编写
注解的问题
配置信息从文件中 转移到了代码中 造成耦合度高
注解什么时候使用
不经常修改的配置信息 可以使用注解
总结
使用resultMap标签自定义字段和属性之间的对应关系
<resultMap>
<id> 一般用于定义主键的映射关系
<result> 一般用于定义其他非主键映射关系
一对一
<resultMap>
<id>
<result>
<association
property 实体类中属性名
javaType 指定属性的数据类型
>
一对多
<resultMap>
<id>
<result>
<collection
property 实体类中集合作为属性的名
ofType 集合元素数据类型
>
多对多
<resultMap>
<id>
<result>
<collection
property 实体类中集合作为属性的名
ofType 集合元素数据类型
>
<association
property 实体类中属性名
javaType 指定属性的数据类型
>
<collection>
不同SQL语句之间相互调用
<resultMap>
<id>
<result>
<association
property 实体类中属性名
javaType 指定属性的数据类型
select namespace + sql语句的id
column 指定被调用SQL语句需要传入的参数
>
懒加载模式 延迟加载
并没有减少连接数据库查询的工作量
让工作量在时间上分散开 在单位时间内 运算压力比较小
缓存技术
一级缓存 默认开启
以SQLSession对象为标志 的缓存 每个sqlSession 都有自己独立 的缓存区
减少连接数据库查询的次数
手动清除缓存 clearCache
SQLsession commit
二级缓存
以namespace 为标志的缓存 mapper为标志的 多个SQLsession使用同一 缓存
核心配置文件中 settings 中开启
在每个mapper中开启
单独的SQL语句也需要开启 (默认开启) useCache true flushCache false