Mybatis学习记录(七)----Mybatis查询缓存
1、 什么是查询缓存
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
为什么要用缓存?
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
2、 一级缓存
2.1 一级缓存工作原理
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
2.2 一级缓存测试
mybatis默认支持一级缓存,不需要在配置文件去配置。
按照上边一级缓存原理步骤去测试。
// mybatis 一级缓存测试
@Test
public void testCache1() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 下边查询使用一个SqlSession
// 第一次发起请求,查询id为1的用户 User user1 = userMapper.findUserById(1); System.out.println(user1); // 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。 // 更新user1的信息 //user1.setAddress("杭州市滨江区江南大道3588号"); //userMapper.updateUserByProperty(user1);
// 执行commit操作去清空缓存
//sqlSession.commit(); // 第二次发起请求,查询id为1的用户
User user2 = userMapper.findUserById(1); System.out.println(user2); sqlSession.close(); }
测试结果:

通过查看日志可以发现,我们调用了两次userMapper.findUserById()方法,但是只发起了一次数据库的请求。
当我们在两次查询之间对数据进行commit操作后,又会是怎样的呢?
先取消掉对应的注释:
// 更新user1的信息
user1.setAddress("杭州市滨江区江南大道3588号");
userMapper.updateUserByProperty(user1);
// 执行commit操作去清空缓存
sqlSession.commit();
再次测试,我们发现,发起了两次数据库请求:就是因为我们执行了commit操作。

2.3 一级缓存应用
正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。
public class UserService{
//开始执行时,开启事务,创建SqlSession对象
//第一次调用mapper的方法findUserById(1)
//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
//方法结束,sqlSession关闭
}
如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
3、二级缓存
3.1 原理

首先开启mybatis的二级缓存。
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。
sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。
3.2 开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
| 参数名 | 描述 | 允许值 | 默认值 |
| cacheEnabled | 对在此配置文件下的所有cache 进行全局性开/关设置。 | true| false | true |

在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。

3.3 调用pojo类实现序列化接口

为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。
3.4 测试方法
// mybatis 二级缓存测试
@Test
public void testCache2() throws Exception { SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
//创建代理对象
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); //第一次发起请求,查询id为1的用户信息
User user1 = userMapper1.findUserById(1); System.out.println(user1); //这里执行关闭操作,将SQLSession中的数据放到二级缓存中
sqlSession1.close(); //使用SQLSession3执行commit操作 /*UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user=userMapper3.findUserById(1);
user.setAddress("重庆市南岸区学府大道");
userMapper3.updateUserByProperty(user);
//执行提交,清空UserMapper下的二级缓存
sqlSession3.commit();
sqlSession3.close();*/ UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); // 第二次发起请求,查询id为1的用户
User user2 = userMapper2.findUserById(1); System.out.println(user2); sqlSession2.close(); }
测试结果:

同理,将代码中的注释取消掉,再次测试:

当我执行了commit操作后,mybatis会将缓存的中的数据先清空,当再次查询时,也会先去缓存中查找,若没有找到,就再次发起SQL请求。
3.5 useCache配置
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
3.6 刷新缓存(就是清空缓存)
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache="true" 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
如下:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
4、mybatis整合ehcache
ehcache是一个分布式缓存框架。
4.1 分布缓存
我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)

不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统 开发。所以要使用分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
4.2 整合方法
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类。

mybatis默认实现cache类是:

4.3 加入ehcache包

4.4 整合ehcache
配置mapper中cache中的type为ehcache对cache接口的实现类型。

4.5 加入ehcache的配置文件
在classpath下配置ehcache.xml

5、二级缓存的应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:
通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
6、二级缓存的局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
Mybatis学习记录(七)----Mybatis查询缓存的更多相关文章
- MyBatis学习总结(七)——Mybatis缓存(转载)
孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(七)--Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的 ...
- 【转】MyBatis学习总结(七)——Mybatis缓存
[转]MyBatis学习总结(七)——Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualC ...
- MyBatis 学习记录5 MyBatis的二级缓存
主题 之前学习了一下MyBatis的一级缓存,主要涉及到BaseExecutor这个类. 现在准备学习记录下MyBatis二级缓存. 配置二级缓存与初始化发生的事情 首先二级缓存默认是不开启的,需要自 ...
- MyBatis 学习记录4 MyBatis的一级缓存
主题 分享记录一下MyBatis的一级缓存相关的学习. Demo public static void firstLevelCache() { init("mybatis-config.xm ...
- MyBatis学习总结(七)——Mybatis缓存
一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...
- MyBatis学习总结(七)——Mybatis缓存
一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...
- MyBatis学习笔记(七)——Mybatis缓存
转自孤傲苍狼的博客:http://www.cnblogs.com/xdp-gacl/p/4270403.html 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓 ...
- 七:MyBatis学习总结(七)——Mybatis缓存
---恢复内容开始--- 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地 ...
- mybatis学习记录七——延迟加载
14 延迟加载 14.1 什么是延迟加载 resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.co ...
- Mybatis学习笔记(七) —— 关联查询
一.一对多查询 需求:查询所有订单信息,关联查询下单用户信息. 注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询.如果从用户信息出发查询用户下的订单信息则 ...
随机推荐
- 基于html5页面滚动背景图片动画效果
基于html5页面滚动背景图片动画效果是一款带索引按钮的页面滚动动画特效代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div id="fullpage&q ...
- 自己动手搭建 MongoDB 环境,并建立一个 .NET HelloWorld 程序测试
关于 MongoDB,下面来自百度百科: MongoDB[1]是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. mongoDB[1] Mon ...
- CSS 布局属性(display,float,clear,visibility,overflow,overflow-x,overflow-y)
display:none | inline | block | list-item | inline-block | table | inline-table | table-caption | ta ...
- 【目录】C#操作Excel组件Spire.XLS系列文章目录
本博客所有文章分类的总目录链接:http://www.cnblogs.com/asxinyu/p/4288836.html 1.C#操作Excel组件Spire.XLS文章目录 1.[原创].NET读 ...
- Java 时间日期系列目录
下面是Java的时间和日期相关文章目录: 01. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar 02. ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- Android 学习笔记 BroadcastReceiver广播...
PS:不断提升自己,是件好事... 学习内容: 1.BroadcastReceiver的使用.. 2.通过BroadcastReceiver去启动Service... 1.BroadcastRecei ...
- ASP.NET MVC和WebForm 轻松实现前端和后端的双重验证 jquery.validate+ValidationSugar
上次不足的改进 可能上一个贴子给大家带来很多误解,所以我这次把DEMO完善了两个版本 [ASP.NET WEBFROM]和[ ASP.NET MVC] 修改了一些BUG,并且修改了一些细了 在上个贴子 ...
- T4语法快速入门
1.什么是T4? T4,即4个T开头的英文字母组合:Text Template Transformation Toolkit.T4(Text Template Transformation Toolk ...
- timestamp的两个属性:CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP
timestamp有两个属性,分别是CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP两种,使用情况分别如下: 1. CURRENT_TIMESTAMP 当要 ...
