MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。MyBatis缓存分为一级缓存和二级缓存。
1、一级缓存
一级缓存:本地缓存,SqlSession级别的缓存。一级缓存是一直开启的,没有办法关闭。
与数据库同一次会话期间,查询到的数据,会放到本地缓存中。以后如果需要相同的数据,直接从缓存中拿,没必要再去查询数据库。
一级缓存失效的情况:
1、sqlSession不同。
2、sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)
3、两次查询之间,执行了增删改操作(这次增删改可能对当前数据有影响)
4、手动清除了一级缓存
package com.ljessie.mybatisdemo;
import com.ljessie.mybatisdemo.dao.StudentDao;
import com.ljessie.mybatisdemo.entity.Student;
import org.apache.ibatis.session.SqlSession;
public class CacheTest {
public static void main(String[] args) {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
try{
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.findStudentByID(2);
System.out.println(student);
//一级缓存失效情况一:
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.findStudentByID(2);
//失效情况二:
// Student student1 = mapper.findStudentByID(3);
//失效情况三:
// mapper.addStudent(new Student(0,"testCache",27,1));
// System.out.println("添加testCache成功");
//失效情况四:
// sqlSession.clearCache();
//
// Student student1 = mapper.findStudentByID(2);
// System.out.println(student1);
//
System.out.println(student == student1);
sqlSession.commit();
}finally {
sqlSession.close();
}
}
}
2、二级缓存
二级缓存:全局缓存,基于namespace级别的缓存,一个namespace对应一个二级缓存。
注意:查出的数据,会默认被放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
工作机制:
1、查询一条数据,这个数据就会被放在一级缓存中。
2、如果当前会话关闭了,一级缓存中的数据,会被保存到二级缓存中。
3、如果sqlSession打开了两个Mapper,则不同namespace查出的数据,会放在自己对应的缓存map中。
使用步骤:
1、开启全局二级缓存配置:mybatis-config.xml
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
2、mapper.xml中,<mapper>标签下添加<cache></cache>节点
<!-- eviction:缓存的回收策略,默认LRU(最近最少使用)还有FIFO、SOFT、WEAK等
flushInterval:缓存刷新间隔,缓存多长时间清空一次,默认不清空,单位为ms
readOnly:是否只读,从缓存中获取数据的操作都是只读操作。默认是false
size:缓存存放多少元素
type:指定自定义缓存的类型,实现Cache接口,然后将全类名写在type里面。
-->
<cache eviction="LRU" flushInterval="600000" size="1024" readOnly="false"/>
3、POJO需要实现序列化接口
public class Student implements Serializable {
//省略其他代码
}
测试类:
package com.ljessie.mybatisdemo;
import com.ljessie.mybatisdemo.dao.StudentDao;
import com.ljessie.mybatisdemo.entity.Student;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class CacheTest {
public static void main(String[] args) {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
try{
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.findStudentByID(2);
System.out.println(student);
sqlSession.close();
//测试二级缓存
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.findStudentByID(2);
System.out.println(student1);
System.out.println(student == student1);
sqlSession2.close();
// sqlSession.commit();
}finally {
// sqlSession.close();
}
}
}
控制台打印:第二次查询命中缓存,并没有执行SQL语句,直接从缓存中取出结果。
C:\develop_tools\Java\jdk1.8.0_201\bin\java.exe -Dvisualvm.id=529755079579900 -javaagent:C:\develop_tools\idea\lib\idea_rt.jar=52285:C:\develop_tools\idea\bin -Dfile.encoding=UTF-8 -classpath C:\develop_tools\Java\jdk1.8.0_201\jre\lib\charsets.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\deploy.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\access-bridge-64.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\cldrdata.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\dnsns.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\jaccess.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\jfxrt.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\localedata.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\nashorn.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\sunec.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\sunjce_provider.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\sunmscapi.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\sunpkcs11.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\ext\zipfs.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\javaws.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\jce.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\jfr.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\jfxswt.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\jsse.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\management-agent.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\plugin.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\resources.jar;C:\develop_tools\Java\jdk1.8.0_201\jre\lib\rt.jar;C:\workspace\mybatis-demo\target\classes;C:\Users\zbw\.m2\repository\org\mybatis\mybatis\3.4.6\mybatis-3.4.6.jar;C:\Users\zbw\.m2\repository\mysql\mysql-connector-java\8.0.16\mysql-connector-java-8.0.16.jar;C:\Users\zbw\.m2\repository\com\google\protobuf\protobuf-java\3.6.1\protobuf-java-3.6.1.jar com.ljessie.mybatisdemo.CacheTest
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1863932867.
Returned connection 1863932867 to pool.
Cache Hit Ratio [com.ljessie.mybatisdemo.dao.StudentDao]: 0.0
Opening JDBC Connection
Checked out connection 1863932867 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6f195bc3]
==> Preparing: select * from student where id = ?
==> Parameters: 3(Integer)
<== Columns: id, name, age, department_id
<== Row: 3, Jessie, 21, 1
<== Total: 1
Student{id=3, name='Jessie', age=21, department=null}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6f195bc3]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6f195bc3]
Returned connection 1863932867 to pool.
Cache Hit Ratio [com.ljessie.mybatisdemo.dao.StudentDao]: 0.5
Student{id=3, name='Jessie', age=21, department=null}
false
Process finished with exit code 0
网友评论