阅读前提:了解mybatis的配置文件,以及mapper的书写。
缓存的概念: 缓存是指存储在计算机上的、以便于访问的一个原始数据集的备份,用于减轻数据库的压力。
缓存的好处:访问速度快
原因:就好比你购买一个商品要去北京进行购买。 一个商人自己从背景购买了很多你要买的东西,你下次购买东西时,直接从商人那里购买 这样效率就提高了很多。
一级缓存
一级缓存是SqlSession级别的缓存,在操作数据库的时需要构造SqlSession对象,在对象中有一个数据结构HashMap用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互不影响的。
分析:
-
什么叫SqlSession级别的缓存。
理解:我们在使用mybatis进行操作数据库的时候通常有以下步骤
a. 加载配置文件。
InputStream in = Resources.getResourcesAsStream("mybatis-config.xml");
b. 获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
c. 获取SqlSession
SqlSession session = sqlSessionFactory.openSession()
d. 获取dao层代理对象
Dao层接口 demo = session.getMapper(Dao层接口.class)
e. 调用方法
demo.api
上面通过session获取的Dao层代理对象所对数据库进行的操作就存储在数据库中。
eg:
当查询的参数不同的时候
-
不同的SqlSession之间的缓存数据区域是互不影响的。
验证code —使用参数2进行查询结果。public void testCache() { //在执行session 的提交修改的时候,要执行commit 这样做的目的是避免脏读 SqlSession session = sqlSessionFactory.openSession(); UserDao userDao = session.getMapper(UserDao.class); User user= userDao.findUserById(2); System.out.println(user); session.close(); SqlSession session1 = sqlSessionFactory.openSession(); userDao = session1.getMapper(UserDao.class); User user1= userDao.findUserById(2); System.out.println(user1); session1.close(); }
Debug结果如下显示触发了两次查询数据库的操作。
二级缓存
二级缓存是mapper级别的缓存,并且默认二级缓存是关闭的需要自己打开。
在同一个程序中开启三个SqlSession 即sqlSession1,sqlSession2, sqlSession3
sqlSession1去查询id为1的用户信息,查询到的结果会存储在二级缓存中
sqlSession2去执行mapper下的sql 执行commit提交,会清空mapper下的二级缓存区域的数据。
sqlSession3 去查询id为1的用户的信息,去缓存中找是否存在数据,如果存在,就直接从缓存中取出数据。
二级缓存和一级缓存的区别。二级缓存的范围更大,多个sqlSession可以共享一个Mapper的二级缓存区域。
如何打开二级缓存。
- 在mybatis-config.xml中的settings中添加下面的配置。
<setting name="cacheEnabled" value="true"/>
- 在相应的mapper下添加
<cache/>
- 查询的pojo类 即结果记得返回类型 实现序列化接口
测试二级缓存代码
例1. 针对于查找来说
public void testCache() {
//在执行session 的提交修改的时候,要执行commit 这样做的目的是避免脏读
SqlSession session = sqlSessionFactory.openSession();
SqlSession session1 = sqlSessionFactory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
User user= userDao.findUserById(2);
System.out.println(user);
session.close();
userDao = session1.getMapper(UserDao.class);
User user1= userDao.findUserById(2);
System.out.println(user1);
session1.close();
}
结果如下:
例2. 针对于mapper下的session执行commit来说
public void testCache() {
//在执行session 的提交修改的时候,要执行commit 这样做的目的是避免脏读
SqlSession session = sqlSessionFactory.openSession();
SqlSession session1 = sqlSessionFactory.openSession();
SqlSession session2 = sqlSessionFactory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
User user= userDao.findUserById(2);
System.out.println(user);
session.close();
//session2
userDao = session2.getMapper(UserDao.class);
User user2 = new User();
user2.setUsername("sofency");
user2.setAddress("西安");
userDao.insertUser(user2);
session2.commit();
session2.close();
userDao = session1.getMapper(UserDao.class);
User user1= userDao.findUserById(2);
System.out.println(user1);
session1.close();
}
执行commit会清空二级缓存
二级缓存的应用场景
对于访问多的查询请求且用户对于查询的结果实时性要求不高,此时可以采用mybatis二级缓存技术降低数据库的访问量,提高访问的速度
业务场景比如,耗时较高的统计分析sql, 电话账单查询sql等
实现的方法如下: 通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化的频率并设置缓存舒心的间隔flushInterval
比如设置为30分钟,60分钟,24小时
二级缓存的局限性
缓存中存储大量的数据,但是当一个数据发生更新的时候执行commit就会将所有的缓存清空。
useCache
useCache 对于mapper中的select配置文件,
如果设置了userCache=“false”,那么该条sql语句每执行一次就会操作数据库一次,不会从缓存中拿取数据,这样做避免了脏读问题。
刷新缓存(清空缓存)
在进行insert或者更新或者删除时,可以在mapper的sql语句中设置flushCache=“true” 这样做可以避免脏读问题,但是我们在执行这些操作的时候会执行session的commit操作,因此也可以不用设置。
分布式缓存ehcache与mybatis的整合
mybatis 无法实现分布式的缓存 需要整合分布式缓存的框架,主要解决的问题就是,不同的服务器之间缓存进行共享的问题。将所有的服务器之间的缓存统一管理。
常见的分布式缓存的框架有Redis和ehcache
整合步骤
1. 将ehcache-core.jar和mybatis-ehcache.jar包添加到lib包下
2. 获取EhcacheCache的全限定路径名
3. 在mapper下的cache里面添加属性type这样就实现了分布式缓存 这样做的目的是更换mybatis默认的缓存容器为ehcache
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
4. 在类路径下设置ehcache.xml 后期好好研究
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="H:\develop\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>