1 mybatis映射文件
1.1 顶级元素标签
标签 作用 cache 该命名空间的缓存配置 cache-ref 引用其它命名空间的缓存配置 resultMap 描述数据库结果集与java对象的映射关系,是最复杂也是最强大的元素 parameterMap 老式风格的参数映射,此元素已被废弃 sql 可被其它语句引用的可重用语句块 insert dao层方法与数据库中插入语句的映射关系 update dao层方法与数据库中更新语句的映射关系 delete dao层方法与数据库中删除语句的映射关系 select dao层方法与数据库中查询语句的映射关
1.2 insert、update、delete标签内属性
属性 描述 id 用来标识跟dao接口中匹配的方法,必须与方法的名字一一对应上 parameterType 可以传入这条语句的形参列表中参数的全限定类名或别名。该属性可选,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset) parameterMap 已废弃 flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:select标签false useCache 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:select标签 true timeout 超时后抛出异常 statementType 用来选择执行sql语句的方式,statement:最基本的jdbc操作,用来表示一个sql语句,不能防止sql注入,prepared:preparestatment:采用预编译方式,防止sql注入,callable:调用存储过程。默认值:PREPARED useGeneratedKeys 设置为true时,当insert或update后,可以获取到表中自动递增的主键值,默认值:false keyProperty 指定useGeneratedKey所获取到的主键要赋值到哪个属性中。如果生成列不止一个,可以用逗号分隔多个属性名称。 不设置该值时,如果未给User中id赋值,且数据库中设计中,对主键id设置了自动递增,插入后,虽然数据库中id字段会有值,但java程序中的User对象的id属性没有值 keyColumn 仅适用于 insert 和 update,设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称 databaseId 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略
< insert id = " insertUser" useGeneratedKeys = " true" keyProperty = " id" >
insert into user(user_name) values(#{userName})
</ insert>
< insert id = " insertUser2" >
< selectKey order = " BEFORE" keyProperty = " id" resultType = " integer" >
select max(id)+1 from user
</ selectKey>
insert into user(id,user_name) values(#{id},#{userName})
</ insert>
1.3 sql标签
< sql id = " sometable" >
${prefix}Table
</ sql>
< sql id = " someinclude" >
from
< include refid = " ${include_target}" />
</ sql>
< select id = " select" resultType = " map" >
select
field1, field2, field3
< include refid = " someinclude" >
< property name = " prefix" value = " Some" />
< property name = " include_target" value = " sometable" />
</ include>
</ select>
1.4 select标签
1.4.1 相关属性
属性 描述 resultType 表示返回的结果类型,此类型只能返回单一的对象,使用较少。当返回的结果是一个集合时,并不需要resultMap,只需要resultType指定集合中的元素类型即可 resultMap 当进行关联查询时,返回的结果的对象中,还包含另一个对象的引用时,又或者表中字段名称和属性名不符时,都需要使用resultMap来自定义结果集合
2 参数传递
2.1 Dao层方法中只有一个参数
基本类型:使用#{随便写} 引用类型:使用#{类的属性名称}
2.2 Dao层方法中多个参数
方案一:通过#{arg0},#{arg1},或者#{param1},#{param2}等方式来获取值
因为mybatis在传入多个参数的时候,会将这些参数封装到一个map中,此时map中的key就是arg0、arg1、param1、param2这些值,但此时无法根据参数的名称来获取具体的值 方案二:可以在Dao层的方法上加入@Param注释,指定方法中参数与sql中绑定参数对照关系
Emp selectEmpByNoAndName ( @Param ( "empno" ) Integer empno, @Param ( "ename" ) String ename) ;
< select id= "selectEmpByNoAndName" resultType= "com.mashibing.bean.Emp" >
select * from emp where empno= #{ empno} and ename= #{ ename}
< / select>
2.3 Dao层方法中使用Map类型的参数
其实就是以xml中#{key}中的key作为map的key,这样就能将map的value,传递给指定占位符
Emp selectEmpByNoAndName2 ( Map< String, Object> map) ;
< select id= "selectEmpByNoAndName2" resultType= "com.mashibing.bean.Emp" >
select * from emp where empno= #{ empno} and ename= #{ ename}
< / select>
3 参数的取值方式
在xml文件中编写sql语句的时候有两种取值的方式,分别是#{}和${}
< select id = " selectEmpByNoAndName" resultType = " com.mashibing.bean.Emp" >
select * from #{t} where empno=${empno} and ename=${ename}
</ select>
使用#{}方式进行取值:采用的是参数预编译的方式,参数的位置使用"?"进行替代,不会出现sql注入的问题
select * from emp where empno= ? and ename= ?
使用
方
式
进
行
取
值
:
采
用
的
是
直
接
跟
s
q
l
语
句
进
行
拼
接
的
方
式
,
当
需
要
动
态
传
入
表
名
、
列
名
时
需
要
使
用
{}方式进行取值:采用的是直接跟sql语句进行拼接的方式,当需要动态传入表名、列名时需要使用
方 式 进 行 取 值 : 采 用 的 是 直 接 跟 s q l 语 句 进 行 拼 接 的 方 式 , 当 需 要 动 态 传 入 表 名 、 列 名 时 需 要 使 用 {}
select * from emp where empno= 7369 and ename= 'SMITH'
4 返回集合类型
当返回值是集合类型的时候,resultType写的是集合中元素的类型
List< Emp> selectAllEmp ( ) ;
< select id = " selectAllEmp" resultType = " com.mashibing.bean.Emp" >
select * from emp
</ select>
如果集合中的元素,没有具体的实体类对应,可以指定元素为map型,map的key为表的列名,map的value为具体值
public List< Map< String, Integer> > getMapList ( ) ;
< select id = " getMapList" resultType = " map" >
select t.ename,b.dname from emp t,dept b where t.deptno=b.deptno
</ select>
返回值也可以是Map类型,也可以表示结果集合
@MapKey ( "empno" )
Map< Integer, Emp> getAllEmpReturnMap ( ) ;
< select id = " getAllEmpReturnMap" resultType = " com.mashibing.bean.Emp" >
select * from emp
</ select>
5 自定义结果集
Dog.java
package com. mashibing. bean;
public class Dog {
private Integer id;
private String name;
private Integer age;
private String gender;
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Integer getAge ( ) {
return age;
}
public void setAge ( Integer age) {
this . age = age;
}
public String getGender ( ) {
return gender;
}
public void setGender ( String gender) {
this . gender = gender;
}
@Override
public String toString ( ) {
return "Dog{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}' ;
}
}
dog.sql
SET FOREIGN_KEY_CHECKS= 0 ;
DROP TABLE IF EXISTS ` dog` ;
CREATE TABLE ` dog` (
` id` int ( 11 ) NOT NULL AUTO_INCREMENT ,
` dname` varchar ( 255 ) DEFAULT NULL ,
` dage` int ( 11 ) DEFAULT NULL ,
` dgender` varchar ( 255 ) DEFAULT NULL ,
PRIMARY KEY ( ` id` )
) ENGINE = InnoDB AUTO_INCREMENT = 4 DEFAULT CHARSET = utf8;
INSERT INTO dog VALUES ( '1' , '大黄' , '1' , '雄' ) ;
INSERT INTO dog VALUES ( '2' , '二黄' , '2' , '雌' ) ;
INSERT INTO dog VALUES ( '3' , '三黄' , '3' , '雄' ) ;
DogDao.java
package com. mashibing. dao;
import com. mashibing. bean. Dog;
public interface DogDao {
public Dog selectDogById ( Integer id) ;
}
DogDao.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.mashibing.dao.DogDao" >
< select id = " selectDogById" resultMap = " myDog" >
select * from dog where id = #{id}
</ select>
< resultMap id = " myDog" type = " com.mashibing.bean.Dog" >
< id column = " id" property = " id" > </ id>
< result column = " dname" property = " name" > </ result>
< result column = " dage" property = " age" > </ result>
< result column = " dgender" property = " gender" > </ result>
</ resultMap>
</ mapper>
6 联合查询
6.1 多对一
Emp.java
package com. mashibing. bean;
import java. util. Date;
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double common;
private Dept dept;
public Emp ( ) {
}
public Emp ( Integer empno, String ename) {
this . empno = empno;
this . ename = ename;
}
public Emp ( Integer empno, String ename, String job, Integer mgr, Date hiredate, Double sal, Double common, Dept dept) {
this . empno = empno;
this . ename = ename;
this . job = job;
this . mgr = mgr;
this . hiredate = hiredate;
this . sal = sal;
this . common = common;
this . dept = dept;
}
public Integer getEmpno ( ) {
return empno;
}
public void setEmpno ( Integer empno) {
this . empno = empno;
}
public String getEname ( ) {
return ename;
}
public void setEname ( String ename) {
this . ename = ename;
}
public String getJob ( ) {
return job;
}
public void setJob ( String job) {
this . job = job;
}
public Integer getMgr ( ) {
return mgr;
}
public void setMgr ( Integer mgr) {
this . mgr = mgr;
}
public Date getHiredate ( ) {
return hiredate;
}
public void setHiredate ( Date hiredate) {
this . hiredate = hiredate;
}
public Double getSal ( ) {
return sal;
}
public void setSal ( Double sal) {
this . sal = sal;
}
public Double getCommon ( ) {
return common;
}
public void setCommon ( Double common) {
this . common = common;
}
public Dept getDept ( ) {
return dept;
}
public void setDept ( Dept dept) {
this . dept = dept;
}
@Override
public String toString ( ) {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", mgr=" + mgr +
", hiredate=" + hiredate +
", sal=" + sal +
", common=" + common +
", dept=" + dept +
'}' ;
}
}
Dept.java
package com. mashibing. bean;
public class Dept {
private Integer deptno;
private String dname;
private String loc;
public Dept ( ) {
}
public Dept ( Integer deptno, String dname, String loc) {
this . deptno = deptno;
this . dname = dname;
this . loc = loc;
}
public Integer getDeptno ( ) {
return deptno;
}
public void setDeptno ( Integer deptno) {
this . deptno = deptno;
}
public String getDname ( ) {
return dname;
}
public void setDname ( String dname) {
this . dname = dname;
}
public String getLoc ( ) {
return loc;
}
public void setLoc ( String loc) {
this . loc = loc;
}
@Override
public String toString ( ) {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}' ;
}
}
EmpDao.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.mashibing.dao.EmpDao" >
< select id = " selectEmpAndDept" resultMap = " empDept" >
select * from emp left join dept on emp.deptno = dept.deptno where empno = #{empno};
</ select>
-->
< resultMap id = " empDept" type = " com.mashibing.bean.Emp" >
< id column = " empno" property = " empno" > </ id>
< result column = " ename" property = " ename" > </ result>
< result column = " job" property = " job" > </ result>
< result column = " mgr" property = " mgr" > </ result>
< result column = " hiredate" property = " hiredate" > </ result>
< result column = " sal" property = " sal" > </ result>
< result column = " comm" property = " common" > </ result>
< association property = " dept" javaType = " com.mashibing.bean.Dept" >
< id column = " deptno" property = " deptno" > </ id>
< result column = " dname" property = " dname" > </ result>
< result column = " loc" property = " loc" > </ result>
</ association>
</ resultMap>
</ mapper>
EmpDao.java
public Emp selectEmpAndDept ( Integer empno) ;
Test
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
Emp emp = mapper. selectEmpAndDept ( 7369 ) ;
System. out. println ( emp) ;
6.2 一对多
Dept.java
package com. mashibing. bean;
import java. util. List;
public class Dept {
private Integer deptno;
private String dname;
private String loc;
private List< Emp> emps;
public Dept ( ) {
}
public Dept ( Integer deptno, String dname, String loc) {
this . deptno = deptno;
this . dname = dname;
this . loc = loc;
}
public Integer getDeptno ( ) {
return deptno;
}
public void setDeptno ( Integer deptno) {
this . deptno = deptno;
}
public String getDname ( ) {
return dname;
}
public void setDname ( String dname) {
this . dname = dname;
}
public String getLoc ( ) {
return loc;
}
public void setLoc ( String loc) {
this . loc = loc;
}
public List< Emp> getEmps ( ) {
return emps;
}
public void setEmps ( List< Emp> emps) {
this . emps = emps;
}
@Override
public String toString ( ) {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
", emps=" + emps +
'}' ;
}
}
DeptDao.java
public Dept getDeptAndEmps ( Integer deptno) ;
DeptDao.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.mashibing.dao.DeptDao" >
< select id = " getDeptAndEmps" resultMap = " deptEmp" >
select * from dept left join emp on dept.deptno = emp.deptno where dept.deptno=#{deptno}
</ select>
< resultMap id = " deptEmp" type = " com.mashibing.bean.Dept" >
< id property = " deptno" column = " deptno" > </ id>
< result property = " dname" column = " dname" > </ result>
< result property = " loc" column = " loc" > </ result>
< collection property = " emps" ofType = " com.mashibing.bean.Emp" >
< id property = " empno" column = " empno" > </ id>
< result column = " ename" property = " ename" > </ result>
< result column = " job" property = " job" > </ result>
< result column = " mgr" property = " mgr" > </ result>
< result column = " hiredate" property = " hiredate" > </ result>
< result column = " sal" property = " sal" > </ result>
< result column = " comm" property = " common" > </ result>
</ collection>
</ resultMap>
</ mapper>
Test
DeptDao mapper = sqlSession. getMapper ( DeptDao. class ) ;
Dept emp = mapper. getDeptAndEmps ( 20 ) ;
System. out. println ( emp. getEmps ( ) . get ( 1 ) . getEname ( ) ) ;
7 分步查询
7.1 多对一
DeptDao.java
public Dept getDeptAndEmpsBySimple ( Integer deptno) ;
EmpDao.java
Emp selectEmpAndDeptBySimple ( Integer empno) ;
DeptDao.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.mashibing.dao.DeptDao" >
< select id = " getDeptAndEmpsBySimple" resultType = " com.mashibing.bean.Dept" >
select * from dept where deptno = #{deptno}
</ select>
</ mapper>
EmpDao.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.mashibing.dao.EmpDao" >
< select id = " selectEmpAndDeptBySimple" resultMap = " simpleEmpAndDept" >
select * from emp where empno = #{empno}
</ select>
< resultMap id = " simpleEmpAndDept" type = " com.mashibing.bean.Emp" >
< id column = " empno" property = " empno" > </ id>
< result column = " ename" property = " ename" > </ result>
< result column = " job" property = " job" > </ result>
< result column = " mgr" property = " mgr" > </ result>
< result column = " hiredate" property = " hiredate" > </ result>
< result column = " sal" property = " sal" > </ result>
< result column = " comm" property = " common" > </ result>
< association property = " dept" select = " com.mashibing.dao.DeptDao.getDeptAndEmpsBySimple" column = " deptno" >
</ association>
</ resultMap>
</ mapper>
Test
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
Emp emp = mapper. selectEmpAndDeptBySimple ( 7369 ) ;
System. out. println ( emp) ;
7.2 一对多
EmpDao.java
Emp selectEmpByStep ( Integer empno) ;
DeptDao.java
public Dept getDeptAndEmpsByStep ( Integer deptno) ;
EmpDao.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.mashibing.dao.EmpDao" >
< select id = " selectEmpByStep" resultType = " com.mashibing.bean.Emp" >
select * from emp where deptno = #{deptno}
</ select>
</ mapper>
DeptDao.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.mashibing.dao.DeptDao" >
< select id = " getDeptAndEmpsByStep" resultMap = " deptEmpByStep" >
select * from dept where deptno = #{deptno}
</ select>
< resultMap id = " deptEmpByStep" type = " com.mashibing.bean.Dept" >
< id property = " deptno" column = " deptno" > </ id>
< result property = " dname" column = " dname" > </ result>
< result property = " loc" column = " loc" > </ result>
< collection property = " emps" select = " com.mashibing.dao.EmpDao.selectEmpByStep" column = " deptno" >
</ collection>
</ resultMap>
</ mapper>
Test
DeptDao mapper = sqlSession. getMapper ( DeptDao. class ) ;
Dept deptAndEmpsByStep = mapper. getDeptAndEmpsByStep ( 10 ) ;
System. out. println ( deptAndEmpsByStep) ;
8 延迟查询
当使用分步查询来关联两个表进行查询时,在真正需要使用关联表中的值时,才发起语句。例如在java程序中dept.getDname时,不会发起其关联的语句,当dept.getEmps时,才会真正发起sql语句 mybatis-config.xml
< settings>
< setting name = " lazyLoadingEnabled" value = " true" />
</ settings>
如果在全局配置中设置了延迟加载,但是希望在某一个sql语句查询的时候不使用延迟策略,可以添加fetchType属性
< association property = " dept" select = " com.mashibing.dao.DeptDao.getDeptAndEmpsBySimple" column = " deptno" fetchType = " eager" />
Test
DeptDao mapper = sqlSession. getMapper ( DeptDao. class ) ;
Dept deptAndEmpsByStep = mapper. getDeptAndEmpsByStep ( 10 ) ;
System. out. println ( deptAndEmpsByStep. getDname ( ) ) ;
System. out. println ( deptAndEmpsByStep. getEmps ( ) ) ;
9 动态sql
动态sql是MyBatis的强大特性之一,此处不是指plsql中的动态sql,此处的动态sql用于替代JDBC中拼接sql语句的方式,可以方便地拼接sql,因此此处的动态sql是不会导致大量硬解析的
9.1 if
EmpDao.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.mashibing.dao.EmpDao" >
< select id = " getEmpByCondition" resultType = " com.mashibing.bean.Emp" >
select * from emp where
< if test = " empno!=null" >
empno > #{empno} and
</ if>
< if test = " ename!=null" >
ename like #{ename} and
</ if>
< if test = " sal!=null" >
sal > #{sal}
</ if>
</ select>
</ mapper>
EmpDao.java
public List< Emp> getEmpByCondition ( Emp emp) ;
Test.java
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
Emp emp = new Emp ( ) ;
emp. setEmpno ( 6500 ) ;
emp. setEname ( "%E%" ) ;
emp. setSal ( 500.0 ) ;
List< Emp> empByCondition = mapper. getEmpByCondition ( emp) ;
for ( Emp emp1 : empByCondition) {
System. out. println ( emp1) ;
}
9.2 where
如果我们传入的参数值有缺失,此时候拼接的sql语句就会变得有问题,例如不传参数或者丢失最后一个参数,那么语句中就会多一个where或者and的关键字 Mybatis中给出了解决方案,使用where元素,此时只会在子元素返回任何内容的情况下才插入where子句。而且,若子句的开头为and或or,where元素也会将它们去除 EmpDao.xml
< select id = " getEmpByCondition" resultType = " com.mashibing.bean.Emp" >
select * from emp
< where>
< if test = " empno!=null" >
empno > #{empno}
</ if>
< if test = " ename!=null" >
and ename like #{ename}
</ if>
< if test = " sal!=null" >
and sal > #{sal}
</ if>
</ where>
</ select>
9.3 trim
可以使用trim定制子句
< select id = " getEmpByCondition" resultType = " com.mashibing.bean.Emp" >
select * from emp
< trim prefix = " where" prefixOverrides = " and" suffixOverrides = " and" >
< if test = " empno!=null" >
empno > #{empno} and
</ if>
< if test = " ename!=null" >
ename like #{ename} and
</ if>
< if test = " sal!=null" >
sal > #{sal} and
</ if>
</ trim>
</ select>
9.4 foreach
一般用于构建in条件语句 EmpDao.xml
< select id = " getEmpByDeptnos" resultType = " com.mashibing.bean.Emp" >
select * from emp where deptno in
< foreach collection = " deptnos" close = " )" index = " idx" item = " deptno" open = " (" separator = " ," >
#{deptno}
</ foreach>
</ select>
EmpDao
public List< Emp> getEmpByDeptnos ( @Param ( "deptnos" ) List deptnos) ;
9.5 choose
之前的if中没法使用else if,choose功能就类似else if,也类似java中的switch语句 EmpDao.xml
< select id = " getEmpByConditionChoose" resultType = " com.mashibing.bean.Emp" >
select * from emp
< where>
< choose>
< when test = " empno!=null" >
empno > #{empno}
</ when>
< when test = " ename!=null" >
ename like #{ename}
</ when>
< when test = " sal!=null" >
sal > #{sal}
</ when>
< otherwise>
1=1
</ otherwise>
</ choose>
</ where>
</ select>
9.6 set
set元素可以忽略不需要更新的列,类似之前where的功能 EmpDao.xml
< update id = " updateEmpByEmpno" >
update emp
< set>
< if test = " empno!=null" >
empno=#{empno},
</ if>
< if test = " ename!=null" >
ename = #{ename},
</ if>
< if test = " sal!=null" >
sal = #{sal}
</ if>
</ set>
< where>
empno = #{empno}
</ where>
</ update>
10 缓存
如果没有缓存,那么每次查询的时候,都需要从数据库加载数据,会造成io问题,所以很多情况下,如果连续执行两条相同的sql语句,可以直接从缓存中读取,如果获取不到,再去数据库中查询,这意味着查询完成的结果,需要放入缓存中 mybatis缓存分类
一级缓存:默认开启,只在当前sqlSession(会话)中缓存,每次查询后,会将数据存储在sqlSession中,每次查询前,先尝试在sqlSession中查询是否已经存在该结果,如果存在,直接从缓存中获取结果。sqlSession关闭后自动失效 二级缓存:需要手动开启,全局范围内缓存,sqlSession关闭后,才会生效 第三方缓存:集成第三方组件充当缓存作用
10.1 一级缓存的使用
下面的案例中,发送了两个相同的请求,但是sql语句仅仅执行了一次,因此意味着第一次查询的时候已经将结果进行了缓存 Test
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
List< Emp> list = mapper. selectAllEmp ( ) ;
for ( Emp emp : list) {
System. out. println ( emp) ;
}
System. out. println ( "--------------------------------" ) ;
List< Emp> list2 = mapper. selectAllEmp ( ) ;
for ( Emp emp : list2) {
System. out. println ( emp) ;
}
10.2 一级缓存失效
10.2.1 开启了多个sqlsession
Test
SqlSession sqlSession = sqlSessionFactory. openSession ( ) ;
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
List< Emp> list = mapper. selectAllEmp ( ) ;
for ( Emp emp : list) {
System. out. println ( emp) ;
}
System. out. println ( "================================" ) ;
SqlSession sqlSession2 = sqlSessionFactory. openSession ( ) ;
EmpDao mapper2 = sqlSession2. getMapper ( EmpDao. class ) ;
List< Emp> list2 = mapper2. selectAllEmp ( ) ;
for ( Emp emp : list2) {
System. out. println ( emp) ;
}
sqlSession. close ( ) ;
sqlSession2. close ( ) ;
10.2.2 为sql语句传递的参数不一致
如果参数为对象,即使二者是同一个对象,但他们属性值不同,也不会走缓存
10.2.3 两次查询间产生了update、insert语句
即使这个update语句和之前的select语句一点关系都没有,再次进行查询也无法使用缓存 但如果是直接数据库或其它连接修改数据,那么第二次查询仍然走缓存,因为sqlSession并不知道第二个sqlSession的存在 EmpDao.java
Emp findEmpByEmpno ( Integer empno) ;
int updateEmp ( Integer empno) ;
EmpDao.xml
< select id = " findEmpByEmpno" resultType = " com.mashibing.bean.Emp" >
select * from emp where empno=#{empno}
</ select>
< update id = " updateEmp" >
update emp set ename='handidiao' where empno=#{empno}
</ update>
Test
SqlSession sqlSession = sqlSessionFactory. openSession ( ) ;
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
Emp empByEmpno = mapper. findEmpByEmpno ( 7369 ) ;
System. out. println ( empByEmpno) ;
System. out. println ( "================================" ) ;
int i = mapper. updateEmp ( 1111 ) ;
System. out. println ( i) ;
System. out. println ( "================================" ) ;
Emp empByEmpno1 = mapper. findEmpByEmpno ( 7369 ) ;
System. out. println ( empByEmpno1) ;
sqlSession. close ( ) ;
10.2.4 两次查询期间,手动清空了缓存
Test
SqlSession sqlSession = sqlSessionFactory. openSession ( ) ;
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
Emp empByEmpno = mapper. findEmpByEmpno ( 1111 ) ;
System. out. println ( empByEmpno) ;
System. out. println ( "================================" ) ;
System. out. println ( "手动清空缓存" ) ;
sqlSession. clearCache ( ) ;
System. out. println ( "================================" ) ;
Emp empByEmpno1 = mapper. findEmpByEmpno ( 1111 ) ;
System. out. println ( empByEmpno1) ;
sqlSession. close ( ) ;
10.3 二级缓存
10.3.1 开启二级缓存
全局配置文件中添加如下配置
< setting name = " cacheEnabled" value = " true" />
需要在使用二级缓存的映射文件(EmpDao.xml)中,使用标签标注
< cache/>
语句中涉及到的所有实体类必须要实现Serializable接口 Test
SqlSession sqlSession = sqlSessionFactory. openSession ( ) ;
SqlSession sqlSession2 = sqlSessionFactory. openSession ( ) ;
EmpDao mapper = sqlSession. getMapper ( EmpDao. class ) ;
EmpDao mapper2 = sqlSession2. getMapper ( EmpDao. class ) ;
Emp empByEmpno = mapper. findEmpByEmpno ( 1111 ) ;
System. out. println ( empByEmpno) ;
sqlSession. close ( ) ;
Emp empByEmpno1 = mapper2. findEmpByEmpno ( 1111 ) ;
System. out. println ( empByEmpno1) ;
sqlSession2. close ( ) ;
10.3.2 cache标签中的属性
eviction:表示缓存淘汰机制,默认是LRU
LRU:最近最少使用的,移除最长时间不被使用的对象 FIFO:先进先出,按照对象进入缓存的顺序来移除 SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象 WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象 flushInternal:设置多长时间进行缓存刷新,单位毫秒。默认情况没有刷新间隔,仅调用语句时刷新缓存 size:引用条数,正整数,表示缓存中可以存储多少个对象,一般不设置,设置的话不要太大,会导致内存溢出 readonly
true:只读缓存,会给所有调用这返回缓存对象的相同实例,因此不安全,修改了一个其他也被修改 false:读写缓存,会返回缓存对象的拷贝(序列化实现),这种方式比较安全,默认为false
10.3.3 二级缓存的作用范围
如果设置了全局的二级缓存配置,可以在select标签中,通过useCache属性,设置不使用二级缓存 增删改操作默认会清空一级缓存和二级缓存,而查询操作不会,这是通过flushCache属性设置的,增删改操作默认值为true,而查询操作默认是false 可以使用sqlSession.clearCache()手动清除一级缓存
10.4 整合第三方缓存
在某些情况下我们也可以自定义实现缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为 Mybatis推荐使用ehcache作为第三方缓存。在github中有使用第三方缓存的相关配置介绍 导入对应的maven依赖
< dependency>
< groupId> org.ehcache</ groupId>
< artifactId> ehcache</ artifactId>
< version> 3.8.1</ version>
</ dependency>
< dependency>
< groupId> org.mybatis.caches</ groupId>
< artifactId> mybatis-ehcache</ artifactId>
< version> 1.2.0</ version>
</ dependency>
< dependency>
< groupId> org.slf4j</ groupId>
< artifactId> slf4j-api</ artifactId>
< version> 2.0.0-alpha1</ version>
</ dependency>
< dependency>
< groupId> org.slf4j</ groupId>
< artifactId> slf4j-log4j12</ artifactId>
< version> 2.0.0-alpha1</ version>
< scope> test</ scope>
</ dependency>
导入ehcache配置文件,名必须为echcache.xml
<?xml version="1.0" encoding="UTF-8"?>
< ehcache xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: noNamespaceSchemaLocation= " http://ehcache.org/ehcache.xsd" >
< diskStore path = " D:\ehcache" />
< defaultCache
maxElementsInMemory = " 1"
maxElementsOnDisk = " 10000000"
eternal = " false"
overflowToDisk = " true"
timeToIdleSeconds = " 120"
timeToLiveSeconds = " 120"
diskExpiryThreadIntervalSeconds = " 120"
memoryStoreEvictionPolicy = " LRU" >
</ defaultCache>
</ ehcache>
EmpDao.xml
< cache type = " org.mybatis.caches.ehcache.EhcacheCache" > </ cache>
11 逆向工程
MyBatis提供了根据数据库中的表,自动生成对应的实体类、bean类以及mapper映射文件的功能 具体配置文档可以在github上的mybatis/generator中找到 数据库表被改动,需要再次使用逆向工程生成文件时,需要先把原来的文件删除
11.1 流程
引入pom依赖
< dependency>
< groupId> org.mybatis.generator</ groupId>
< artifactId> mybatis-generator-core</ artifactId>
< version> 1.4.0</ version>
</ dependency>
< dependency>
< groupId> mysql</ groupId>
< artifactId> mysql-connector-java</ artifactId>
< version> 8.0.16</ version>
</ dependency>
编写逆向工程配置文件:在项目下建立即可,文件名随意,此处为mbg.xml
<!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
< generatorConfiguration>
< context id = " simple" targetRuntime = " MyBatis3" >
< jdbcConnection driverClass = " com.mysql.cj.jdbc.Driver"
connectionURL = " jdbc:mysql://localhost:3306/demo?serverTimezone=UTC"
userId = " root"
password = " c50hst"
/>
< javaModelGenerator targetPackage = " com.mashibing.bean" targetProject = " src/main/java" />
< sqlMapGenerator targetPackage = " com.mashibing.dao" targetProject = " src/main/resources" />
< javaClientGenerator type = " XMLMAPPER" targetPackage = " com.mashibing.dao" targetProject = " src/main/java" />
< table tableName = " emp" domainObjectName = " Emp" enableCountByExample = " false" enableDeleteByExample = " false"
enableUpdateByExample = " false" selectByExampleQueryId = " false" enableSelectByExample = " false" />
< table tableName = " dept" domainObjectName = " Dept" enableCountByExample = " false" enableDeleteByExample = " false"
enableUpdateByExample = " false" selectByExampleQueryId = " false" enableSelectByExample = " false" />
</ context>
</ generatorConfiguration>
编写生成类
package com. mashibing;
import org. mybatis. generator. api. MyBatisGenerator;
import org. mybatis. generator. config. Configuration;
import org. mybatis. generator. config. xml. ConfigurationParser;
import org. mybatis. generator. exception. InvalidConfigurationException;
import org. mybatis. generator. exception. XMLParserException;
import org. mybatis. generator. internal. DefaultShellCallback;
import java. io. File;
import java. io. IOException;
import java. io. InputStream;
import java. sql. SQLException;
import java. util. ArrayList;
import java. util. List;
public class Test {
public static void main ( String[ ] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
List< String> warnings = new ArrayList < String> ( ) ;
boolean overwrite = true ;
File configFile = new File ( "mbg.xml" ) ;
ConfigurationParser cp = new ConfigurationParser ( warnings) ;
Configuration config = cp. parseConfiguration ( configFile) ;
DefaultShellCallback callback = new DefaultShellCallback ( overwrite) ;
MyBatisGenerator myBatisGenerator = new MyBatisGenerator ( config, callback, warnings) ;
myBatisGenerator. generate ( null) ;
}
}