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) ;
}
}