mybatis 使用缓存策略
mybatis中默认开启缓存
1、mybatis中,默认是开启缓存的,缓存的是一个statement对象。
不同情况下是否会使用缓存
同一个SqlSession对象,重复调用同一个id的<select>(id必须相同)的时候,缓存才会生效,两者缺一不可,而是会执行两次sql,并不会使用缓存,因为一个SqlSession就是一个数据库连接。
下面举一个例子,首先看一个PersonMapper.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="lixin.gan.mapper.PersonMapper">
<select id="selectAll1" resultType="Person">
select * from person
</select> <select id="selectAll2" resultType="Person">
select * from person
</select>
</mapper>
针对上面这一个xml来进行测试
不同SqlSession调用同一个id的方法
public class Test {
public static void main(String[] args) throws IOException {
InputStream config = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); SqlSession session1 = factory.openSession();
PersonMapper personMapper1 = session1.getMapper(PersonMapper.class);
personMapper1.selectAll1(); SqlSession session2 = factory.openSession();
PersonMapper personMapper2 = session2.getMapper(PersonMapper.class);
personMapper2.selectAll1();
}
}
上面这个代码中,创建了两个不同的sqlsession(两个数据库连接),虽然调用的是同一个id对应的方法,但是其实sql语句是执行了两次,利用log4j打印的日志如下:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
同一个SqlSession调用不同id,但是sql相同的方法
public class Test {
public static void main(String[] args) throws IOException { InputStream config = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); SqlSession session1 = factory.openSession();
PersonMapper personMapper1 = session1.getMapper(PersonMapper.class);
personMapper1.selectAll1();
personMapper1.selectAll2();
}
}
上面这个代码,虽然只创建了一个SqlSession,使用这个SqlSession去调用了两个方法,这两个方法的id不同,一个是selectAll1,另一个是selectAll2,即使两个方法里面的sql相同,也是不会使用缓存的,所以sql语句仍然会执行了两次,利用log4j打印的日志依旧依旧是:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
同一个SqlSession,调用同一个id的方法。
public class Test {
public static void main(String[] args) throws IOException { InputStream config = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); SqlSession session1 = factory.openSession();
PersonMapper personMapper1 = session1.getMapper(PersonMapper.class);
personMapper1.selectAll1();
personMapper1.selectAll1();
}
}
虽然上面这段代码,进了两次selectAll1()操作,但是因为是一个SqlSession,并且方法id相同,所以,会使用缓存,使用log4j打印的日志显示,只进行了一次查询:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
一级缓存与二级缓存
前面已经看到了,使用缓存的两个必要条件:1、同一个SqlSession;2、调用同一个id的方法。
但是有时候,情况是这样的,多个用户请求某个数据,其实执行的sql都是一样的,但是因为是不同用户,所以,就会产生多个SqlSession,多个SqlSession调用同一个id的方法,仍然不会使用缓存。
这个时候,其实是存在资源浪费的问题,既然他们需要的数据是一样的,那么何必再重复查询一次呢,如果数据量很大,重复查询一次,岂不是耗费更多的资源?
mybatis提供了解决办法---二级缓存。方法就是:修改mapper文件,增加cache标签。
前面说到的缓存其实一级缓存,另外还有二级缓存:
1、一级缓存是SqlSession缓存,缓存的数据存在每一个SqlSession各自的空间中。
2、二级缓存是SqlSessionFactory缓存,缓存的数据存在每一个SqlSessionFactory各自的空间中。
一级缓存与二级缓存的作用范围
1、一级缓存的作用范围是同一个SqlSession,并且只有当调用的方法id相同,才可以使用本SqlSession中的缓存。
2、二级缓存的作用范围是由同一个SqlSessionFactory对象创建出的所有SqlSession,不同的SqlSessionFactory创建的SqlSession不能共享二级缓存。
一级缓存与二级缓存的原理
当一个SqlSession要查数据,会先查看一级缓存中是不是存在缓存,如果存在缓存,则直接从当前SqlSession的一级缓存中读取数据。如果不存在缓存,那么就会执行sql命令,去数据库中查询数据,并且将查询出的数据,保存到当前SqlSession对应的一级缓存中。可以调用clearCache()来清除当前SqlSession的一级缓存数据。
各个SqlSession的一级缓存是不能共享的。但是二级缓存是可以共享的,于是乎,可以将一级缓存中的数据,放到二级缓存中,然后其他SqlSession在查询之前,首先到一级缓存中查看是否有数据,如果一级缓存有数据,就从一级缓存中取数据;如果一级缓存中没有数据,如果在mapper.xml中设置了cache,那么可以继续查询二级缓存,如果二级缓存中存在要查询到数据,那么就从二级缓存中读取数据,否则就从数据库中读取数据。
使用二级缓存的前提
二级缓存共享数据的一个前提是:一个SqlSession调用close()之后,才会将一级缓存中的数据放到二级缓存中,如果不关闭SqlSession,数据只会存在于一级缓存中,数据不会发生共享。
这个前提很重要!
什么时候使用二级缓存
当某些数据频繁被使用,并且很少被修改的情况。
如果数据频繁修改,一定不要放到二级缓存中。
测试使用二级缓存
修改后的PersonMapper.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="lixin.gan.mapper.PersonMapper">
<cache readOnly="true"></cache>
<select id="selectAll1" resultType="Person">
select * from person
</select> <select id="selectAll2" resultType="Person">
select * from person
</select>
</mapper>
正确、正常的测试代码
public class Test {
public static void main(String[] args) throws IOException { InputStream config = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); SqlSession session1 = factory.openSession();
PersonMapper personMapper1 = session1.getMapper(PersonMapper.class);
personMapper1.selectAll1(); // 可以调用clearCache来清空当前SqlSession的缓存
//session1.clearCache(); // 需要将session关闭之后,才会将数据放进二级缓存,否则数据不会放进二级缓存
session1.close(); SqlSession session2 = factory.openSession();
PersonMapper personMapper2 = session2.getMapper(PersonMapper.class);
personMapper2.selectAll1(); }
}
log4j记录的日志如下:
org.apache.ibatis.cache.decorators.LoggingCache - line:62 - Cache Hit Ratio [lixin.gan.mapper.PersonMapper]: 0.0
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
org.apache.ibatis.cache.decorators.LoggingCache - line:62 - Cache Hit Ratio [lixin.gan.mapper.PersonMapper]: 0.5
不关闭SqlSession,没有发生共享的测试
public class Test {
public static void main(String[] args) throws IOException { InputStream config = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); SqlSession session1 = factory.openSession();
PersonMapper personMapper1 = session1.getMapper(PersonMapper.class);
personMapper1.selectAll1(); // 可以调用clearCache来清空当前SqlSession的缓存
//session1.clearCache(); // 需要将session关闭之后,才会将数据放进二级缓存,否则数据不会放进二级缓存
//session1.close();
// 此处没有关闭session1,所以数据不会放进二级缓存中 SqlSession session2 = factory.openSession();
PersonMapper personMapper2 = session2.getMapper(PersonMapper.class);
personMapper2.selectAll1(); }
}
log4j打印的日志很清楚的记录了上面的代码,执行了两次sql,因为数据没有放进二级缓存,在session2在一级缓存和二级缓存中都没有发现缓存,所以也要执行一次sql。
org.apache.ibatis.cache.decorators.LoggingCache - line:62 - Cache Hit Ratio [lixin.gan.mapper.PersonMapper]: 0.0
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
org.apache.ibatis.cache.decorators.LoggingCache - line:62 - Cache Hit Ratio [lixin.gan.mapper.PersonMapper]: 0.0
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Preparing: select * from person
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - ==> Parameters:
org.apache.ibatis.logging.jdbc.BaseJdbcLogger - line:139 - <== Total: 4
mybatis 使用缓存策略的更多相关文章
- Mybatis Cache 缓存策略
Mybatis Cache 缓存策略 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用 ...
- MyBatis缓存策略
MyBatis 提供了一级缓存和二级缓存策略,一级缓存是作用在SqlSession级别上的,而二级缓存则是作用在Mapper级别上的( 即作用在 namespace上),MyBatis 默认是开启的一 ...
- Mybatis 缓存策略
听极客学院笔记 使用mybatis的缓存需要以下三步 一.在mybatis的config.xml中开启缓存 <settings> <setting name="cacheE ...
- Spring+SpringMVC+MyBatis深入学习及搭建(八)——MyBatis查询缓存
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6956206.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(七)——My ...
- mybatis一级缓存二级缓存
一级缓存 Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言.所以在参数和SQL完全一样的情况下,我们使用同一个SqlSess ...
- 深入浅出mybatis之缓存机制
目录 前言 准备工作 MyBatis默认缓存设置 缓存实现原理分析 参数localCacheScope控制的缓存策略 参数cacheEnabled控制的缓存策略 总结 前言 提到缓存,我们都会不约而同 ...
- Mybatis的缓存
1.缓存是什么 在 Mybatis 里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录,从而提高查询的效率. Mybatis 的 ...
- mybatis 二级缓存
Mybatis读取缓存次序: 先从二级缓存中获取数据,如果有直接获取,如果没有进行下一步: 从一级缓存中取数据,有直接获取,如果没有进行下一步: 到数据库中进行查询,并保存到一级缓存中: 当sqlSe ...
- mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache
1.1 什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 s ...
随机推荐
- 【Nginx】使用nginx反向代理IIS实现80端口的解放
下载版本: 官网地址:http://nginx.org/en/download.html 我使用了稳定版本. 下载完成之后进行目录解压,解压之后大概就是这个样子: 网上很多人写这些了想了解概念的百度一 ...
- C#面试分享:单例模式
C#面试分享:单例模式 提问1:请给出单例模式的实现: 答: public class Animal { private static Animal _instance = null; private ...
- Bable实现由ES6转译为ES5
Babel是一个广泛使用的转码器,可以将ES6代码转译为ES5代码,从而在现有环境下执行. 举例说明: 转译前(ES6格式)代码如下: let User = { name : '张三', age : ...
- arcgis api 3.x for js 入门开发系列二不同地图服务展示(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- border,padding,margin盒模型理解
安静的敲着键盘,已势不可挡的姿势逼近php,我想我是一个幸福的人,未来不可期,做好现在,偶尔写着自己能看懂的API,慢慢悠悠的回味一下前端基础知识. 本文盒模型理解. <!DOCTYPE htm ...
- 广州.NET微软技术俱乐部微信群有用信息集锦(10) - 大量json数据压缩方案
这是广州.NET微软技术俱乐部微信群有用信息集锦系列的其中一篇文章. 刚才微信群里有人问:“对于大量json数据返回的时候,有用过什么压缩方案吗?” 大家都给与了回答和帮助.包括: 开启gzi ...
- SpringBoot的自动配置原理过程解析
SpringBoot的最大好处就是实现了大部分的自动配置,使得开发者可以更多的关注于业务开发,避免繁琐的业务开发,但是SpringBoot如此好用的 自动注解过程着实让人忍不住的去了解一番,因为本文的 ...
- 借助表达式树感受不一样的CRUD
借助表达式树感受不一样的CRUD Intro 最近有个想法,想不写 sql 语句,做一个类似于 ORM 的东西,自己解析表达式树,生成要执行的 sql 语句,最后再执行 sql 语句,返回相应结果. ...
- MongoDB在已有账号的实例下还原数据库报错的分析(error applying oplog)
一. 背景 今天在MongoDB 4.0.4版本下,在还原恢复数据库时报错. 主要错误为: Failed: restore error: error applying oplog: applyOps: ...
- Mysql中联合索引的最左匹配原则
在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先. 如果我们建立了一个2列的联合索引(col1,col2),实际上已经建立了两个联合索引(col1).(col1,col2); 如果有一 ...