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 使用缓存策略的更多相关文章

  1. Mybatis Cache 缓存策略

    Mybatis Cache 缓存策略 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用 ...

  2. MyBatis缓存策略

    MyBatis 提供了一级缓存和二级缓存策略,一级缓存是作用在SqlSession级别上的,而二级缓存则是作用在Mapper级别上的( 即作用在 namespace上),MyBatis 默认是开启的一 ...

  3. Mybatis 缓存策略

    听极客学院笔记 使用mybatis的缓存需要以下三步 一.在mybatis的config.xml中开启缓存 <settings> <setting name="cacheE ...

  4. Spring+SpringMVC+MyBatis深入学习及搭建(八)——MyBatis查询缓存

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6956206.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(七)——My ...

  5. mybatis一级缓存二级缓存

    一级缓存 Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言.所以在参数和SQL完全一样的情况下,我们使用同一个SqlSess ...

  6. 深入浅出mybatis之缓存机制

    目录 前言 准备工作 MyBatis默认缓存设置 缓存实现原理分析 参数localCacheScope控制的缓存策略 参数cacheEnabled控制的缓存策略 总结 前言 提到缓存,我们都会不约而同 ...

  7. Mybatis的缓存

    1.缓存是什么 在 Mybatis 里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录,从而提高查询的效率. Mybatis 的 ...

  8. mybatis 二级缓存

    Mybatis读取缓存次序: 先从二级缓存中获取数据,如果有直接获取,如果没有进行下一步: 从一级缓存中取数据,有直接获取,如果没有进行下一步: 到数据库中进行查询,并保存到一级缓存中: 当sqlSe ...

  9. mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache

    1.1  什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 s ...

随机推荐

  1. C#调用Oracle的存储过程时,连接字符串需要配置PLSQLRSet=1

    C#调用Oracle的存储过程时, 如果有个SYS_REFCURSOR的Output参数存储时, web.config文件中的连接字符串需要配置PLSQLRSet=1, 否则可能会报这个错:参数个数或 ...

  2. aspx 页面中 js 引用与页面后台的数据交互 --【 后台调用 js 】

    js 中调用后台方法   一.用Response.Write方法 Response.Write("<script type='text/javascript'>alert(&qu ...

  3. python学习笔记(十 三)、网络编程

    最近心情有点儿浮躁,难以静下心来 Python提供了强大的网络编程支持,很多库实现了常见的网络协议以及基于这些协议的抽象层,让你能够专注于程序的逻辑,而无需关心通过线路来传输比特的问题. 1 几个网络 ...

  4. Java学习笔记——判断字符Character类

    常用方法 下面所说的均是静态方法,也就是可以不创建对象直接调用 例:Character.isLetter(char c); isLetter 判断参数是否为字母(不分大小写),返回结果 isDigit ...

  5. Selenium自动化-入门1

    起初写博客是为了妹子学习,现在发现忽略了最基础的Selenium教程,所以:从本博客开始编辑 Selenium 入门知识.(学好Java) Selenium 入门 1:(学好Java) 录制回放,简单 ...

  6. 博弈论进阶之Every-SG

    Every-SG 给定一张无向图,上面有一些棋子,两个顶尖聪明的人在做游戏,每人每次必须将可以移动的棋子进行移动,不能移动的人输 博弈分析 题目中的要求实际是"不论前面输与否,只要最后一个棋 ...

  7. Dynamics 365测试和启用邮箱时候一直显示“安排电子邮件配置测试”怎么办?

    摘要: 本人微信公众号:微软动态CRM专家罗勇 ,回复284或者20181125可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me ...

  8. 探究高级的Kotlin Coroutines知识

    要说程序如何从简单走向复杂, 线程的引入必然功不可没, 当我们期望利用线程来提升程序效能的过程中, 处理线程的方式也发生了从原始时代向科技时代发生了一步一步的进化, 正如我们的Elisha大神所著文章 ...

  9. Python第十一天 异常处理 glob模块和shlex模块 打开外部程序和subprocess模块 subprocess类 Pipe管道 operator模块 sorted函数 os模块 hashlib模块 platform模块 csv模块

    Python第十一天    异常处理  glob模块和shlex模块    打开外部程序和subprocess模块  subprocess类  Pipe管道  operator模块   sorted函 ...

  10. mysql备份与还原!

    一.备份常用操作基本命令 1.备份命令mysqldump格式 格式:mysqldump -h主机名  -P端口 -u用户名 -p密码 –database 数据库名 > 文件名.sql 2.备份M ...