MyBatis框架——缓存机制
使⽤缓存机制的作⽤也是减少 Java 应⽤程序与数据库的交互次数,从⽽提升程序的运⾏效率。
⽐如第 ⼀次查询出某个对象之后,MyBatis 会⾃动将其存⼊缓存,当下⼀次查询同⼀个对象时,就可以直接从 缓存中获取,不必再次访问数据库。
MyBatis 有两种缓存:⼀级缓存和⼆级缓存。
MyBatis ⾃带⼀级缓存,并且⽆法关闭,⼀直存在,⼀级缓存的数据存储在 SqlSession 中,它的范围 就是在⼀个SqlSession 对象中。
当使⽤同⼀个 SqlSession 对象执⾏查询操作时,第⼀次的执⾏结果会 ⾃动存⼊ SqlSession 缓存中,第⼆次查询时直接从缓存中获取即可。
如果是不同的 SqlSession 对象,则缓存数据⽆法同步。
同时需要注意,为了保证数据的⼀致性,如果 SqlSession 执⾏了增加、删除、修改操作,MyBatis 会 ⾃动清空 SqlSession 缓存中存储的数据。
⼀级缓存不需要进⾏任何配置,直接使⽤即可。
MyBatis ⼆级缓存是⽐⼀级缓存作⽤域更⼤的缓存机制,它是 Mapper 级别,只要是同⼀个 Mapper, ⽆论使⽤多少个SqlSession 来操作,数据都是共享的,多个不同的 SqlSession 可以共⽤⼆级缓存。
MyBatis ⼆级缓存默认是关闭的,需要使⽤时可以通过配置⼿动开启。
- 一级缓存,示例:
测试类
package com.sunjian.test; import com.sunjian.entity.Classes; import com.sunjian.entity.Order; import com.sunjian.entity.User; import com.sunjian.repository.ClassesRepository; import com.sunjian.repository.OrderRepository; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import sun.reflect.generics.repository.ClassRepository; import java.io.InputStream; /** * @author sunjian * @date 2020/3/22 10:20 */ public class TestCache { public static void main(String[] args) { // Mapper 代理实现自定义接口 InputStream inputStream = User.class.getClassLoader().getResourceAsStream("config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 ClassesRepository classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes = classesRepository.findClassById(2); System.out.println(classes); Classes classes1 = classesRepository.findClassById(2); System.out.println(classes1); } }
Opening JDBC Connection Created connection 793315160. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f490758] ==> Preparing: select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = ? ==> Parameters: 2(Integer) <== Columns: cid, cname, sid, sname, score, tel, address <== Row: 2, 2班, 1, 张三, 90, 15510211111, 大望路 <== Row: 2, 2班, 3, 赵六, 87, 18800110011, 回龙观 <== Total: 2 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]} Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]}
查询两次,只执行一次SQL。
查询一次后,关闭sqlSession,创建新的sqlSession后,再查询
package com.sunjian.test; import com.sunjian.entity.Classes; import com.sunjian.entity.Order; import com.sunjian.entity.User; import com.sunjian.repository.ClassesRepository; import com.sunjian.repository.OrderRepository; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import sun.reflect.generics.repository.ClassRepository; import java.io.InputStream; /** * @author sunjian * @date 2020/3/22 10:20 */ public class TestCache { public static void main(String[] args) { // Mapper 代理实现自定义接口 InputStream inputStream = User.class.getClassLoader().getResourceAsStream("config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 ClassesRepository classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes = classesRepository.findClassById(2); System.out.println(classes); sqlSession.close(); sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes1 = classesRepository.findClassById(2); System.out.println(classes1); } }
Opening JDBC Connection Created connection 793315160. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f490758] ==> Preparing: select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = ? ==> Parameters: 2(Integer) <== Columns: cid, cname, sid, sname, score, tel, address <== Row: 2, 2班, 1, 张三, 90, 15510211111, 大望路 <== Row: 2, 2班, 3, 赵六, 87, 18800110011, 回龙观 <== Total: 2 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]} Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f490758] Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f490758] Returned connection 793315160 to pool. Opening JDBC Connection Checked out connection 793315160 from pool. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f490758] ==> Preparing: select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = ? ==> Parameters: 2(Integer) <== Columns: cid, cname, sid, sname, score, tel, address <== Row: 2, 2班, 1, 张三, 90, 15510211111, 大望路 <== Row: 2, 2班, 3, 赵六, 87, 18800110011, 回龙观 <== Total: 2 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]}
可以看到执行了两次SQL。
- 二级缓存,示例:
MyBatis 可以使⽤⾃带的⼆级缓存,也可以使⽤第三⽅的 ehcache ⼆级缓存。
MyBatis ⾃带的⼆级缓存,具体步骤如下。
1、config.xml 中配置开启⼆级缓存
<settings> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true"></setting> </settings>
2、ClassesRepository.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="com.sunjian.repository.ClassesRepository"> <cache></cache> <!-- 一对多 --> <resultMap id="classMap" type="com.sunjian.entity.Classes"> <id property="id" column="cid"></id> <result property="name" column="cname"></result> <collection property="students" ofType="com.sunjian.entity.Student"> <id property="id" column="sid"></id> <result property="name" column="sname"></result> <result property="score" column="score"></result> <result property="tel" column="tel"></result> <result property="address" column="address"></result> </collection> </resultMap> <select id="findClassById" parameterType="java.lang.Integer" resultMap="classMap"> select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = #{id} </select> </mapper>
3、Classes 实体类实现 Serializable 接⼝。
package com.sunjian.entity; import java.io.Serializable; import java.util.List; /** * @author sunjian * @date 2020/3/22 14:20 */ public class Classes implements Serializable { private Integer id; private String name; private List<Student> students; @Override public String toString() { return "Classes{" + "id=" + id + ", name='" + name + '\'' + ", students=" + students + '}'; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
4、运行测试类
package com.sunjian.test; import com.sunjian.entity.Classes; import com.sunjian.entity.Order; import com.sunjian.entity.User; import com.sunjian.repository.ClassesRepository; import com.sunjian.repository.OrderRepository; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import sun.reflect.generics.repository.ClassRepository; import java.io.InputStream; /** * @author sunjian * @date 2020/3/22 10:20 */ public class TestCache { public static void main(String[] args) { // Mapper 代理实现自定义接口 InputStream inputStream = User.class.getClassLoader().getResourceAsStream("config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 ClassesRepository classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes = classesRepository.findClassById(2); System.out.println(classes); sqlSession.close(); sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes1 = classesRepository.findClassById(2); System.out.println(classes1); } }
Opening JDBC Connection Created connection 1738236591. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@679b62af] ==> Preparing: select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = ? ==> Parameters: 2(Integer) <== Columns: cid, cname, sid, sname, score, tel, address <== Row: 2, 2班, 1, 张三, 90, 15510211111, 大望路 <== Row: 2, 2班, 3, 赵六, 87, 18800110011, 回龙观 <== Total: 2 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]} Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@679b62af] Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@679b62af] Returned connection 1738236591 to pool. Cache Hit Ratio [com.sunjian.repository.ClassesRepository]: 0.5 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]}
可以看出,即使在第一次查询后,关闭了sqlSession,创建新的sqlSession再次查询时,也是只执行了一次SQL。
- 使⽤第三⽅的 ehcache ⼆级缓存
1、pom.xml 导⼊ ehcache 相关依赖
<!-- 把ehcache整合到mybatis中 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.4.3</version> </dependency>
2、在 resources 路径下创建 ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore/> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
3、config.xml 中配置开启⼆级缓存
<settings> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true"></setting> </settings>
4、ClassesRepository.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="com.sunjian.repository.ClassesRepository"> <!-- myBatis自带二级缓存 --> <!--<cache></cache>--> <!-- 第三方cache二级缓存 --> <cache type="org.mybatis.caches.ehcache.EhcacheCache"> <!-- 缓存创建之后,最后⼀次访问缓存的时间⾄失效的时间间隔 --> <property name="timeToIdleSeconds" value="3600"/> <!-- 缓存⾃创建时间起⾄失效的时间间隔 --> <property name="timeToLiveSeconds" value="3600"/> <!-- 缓存回收策略,LRU 移除近期最少使⽤的对象 --> <property name="memoryStoreEvictionPolicy" value="LRU"/> </cache> <!-- 一对多 --> <resultMap id="classMap" type="com.sunjian.entity.Classes"> <id property="id" column="cid"></id> <result property="name" column="cname"></result> <collection property="students" ofType="com.sunjian.entity.Student"> <id property="id" column="sid"></id> <result property="name" column="sname"></result> <result property="score" column="score"></result> <result property="tel" column="tel"></result> <result property="address" column="address"></result> </collection> </resultMap> <select id="findClassById" parameterType="java.lang.Integer" resultMap="classMap"> select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = #{id} </select> </mapper>
5、实体类不需要实现序列化接⼝
package com.sunjian.entity; import java.util.List; /** * @author sunjian * @date 2020/3/22 14:20 */ public class Classes { private Integer id; private String name; private List<Student> students; @Override public String toString() { return "Classes{" + "id=" + id + ", name='" + name + '\'' + ", students=" + students + '}'; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
6、运行测试类
package com.sunjian.test; import com.sunjian.entity.Classes; import com.sunjian.entity.Order; import com.sunjian.entity.User; import com.sunjian.repository.ClassesRepository; import com.sunjian.repository.OrderRepository; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import sun.reflect.generics.repository.ClassRepository; import java.io.InputStream; /** * @author sunjian * @date 2020/3/22 10:20 */ public class TestCache { public static void main(String[] args) { // Mapper 代理实现自定义接口 InputStream inputStream = User.class.getClassLoader().getResourceAsStream("config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 ClassesRepository classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes = classesRepository.findClassById(2); System.out.println(classes); sqlSession.close(); sqlSession = sqlSessionFactory.openSession(); // 获取接口的处理对象 classesRepository = sqlSession.getMapper(ClassesRepository.class); Classes classes1 = classesRepository.findClassById(2); System.out.println(classes1); } }
Opening JDBC Connection Created connection 952486988. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@38c5cc4c] ==> Preparing: select c.id cid, c.name cname, s.id sid, s.name sname, s.score, s.tel, s.address from classes c, student s where s.cid = c.id and c.id = ? ==> Parameters: 2(Integer) <== Columns: cid, cname, sid, sname, score, tel, address <== Row: 2, 2班, 1, 张三, 90, 15510211111, 大望路 <== Row: 2, 2班, 3, 赵六, 87, 18800110011, 回龙观 <== Total: 2 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]} Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@38c5cc4c] Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@38c5cc4c] Returned connection 952486988 to pool. Cache Hit Ratio [com.sunjian.repository.ClassesRepository]: 0.5 Classes{id=2, name='2班', students=[Student{id=1, name='张三', score=90, tel='15510211111', address='大望路', classes=null, course=null}, Student{id=3, name='赵六', score=87, tel='18800110011', address='回龙观', classes=null, course=null}]}
同样可以看出,即使在第一次查询后,关闭了sqlSession,创建新的sqlSession再次查询时,也是只执行了一次SQL。
OK.
MyBatis框架——缓存机制的更多相关文章
- mybatis的缓存机制及用例介绍
在实际的项目开发中,通常对数据库的查询性能要求很高,而mybatis提供了查询缓存来缓存数据,从而达到提高查询性能的要求. mybatis的查询缓存分为一级缓存和二级缓存,一级缓存是SqlSessio ...
- mybatis(四)缓存机制
转载:https://www.cnblogs.com/wuzhenzhao/p/11103043.html 缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力.跟Hibe ...
- 深入浅出mybatis之缓存机制
目录 前言 准备工作 MyBatis默认缓存设置 缓存实现原理分析 参数localCacheScope控制的缓存策略 参数cacheEnabled控制的缓存策略 总结 前言 提到缓存,我们都会不约而同 ...
- MyBatis - 5.缓存机制
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. MyBatis系统中默认定义了两级缓存. 一级缓存和二级缓存. 1.默认情况下,只有一级缓存( ...
- MyBatis 的缓存机制
缓存机制可以减轻数据库的压力,原理是在第一查询时,将查询结果缓存起来,之后再查询同样的sql, 不是真的去查询数据库,而是直接返回缓存中的结果. 缓存可以降低数据库的压力,但同时可能无法得到最新的结果 ...
- mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache
1.1 什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 s ...
- mybatis的缓存机制
一级缓存: MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效) packa ...
- 聊聊MyBatis缓存机制【美团-推荐】
聊聊MyBatis缓存机制 2018年01月19日 作者: 凯伦 文章链接 18778字 38分钟阅读 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用My ...
- 聊聊MyBatis缓存机制
https://tech.meituan.com/mybatis_cache.html 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用MyBatis的默认 ...
随机推荐
- IOUtils和FileUtils的学习笔记
pom文件导入依赖import org.apache.commons.io.FileUtils; <dependency> <groupId>commons-io</gr ...
- [洛谷P3386] [模板] 二分图匹配 (匈牙利算法)
题目传送门 毒瘤出题人zzk出了个二分图匹配的题(18.10.04模拟赛T2),逼我来学二分图匹配. 网络流什么的llx讲完之后有点懵,还是匈牙利比较好理解(绿与被绿). 对于左边的点一个一个匹配,记 ...
- Mac下如何使用homebrew
Homebrew简称brew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件. 常用的命令: 搜索软件:brew search 软件名,如brew search wget ...
- ajax async异步
async默认的设置值为true,这种情况为异步方式,就是说当ajax发送请求后,在等待server端返回的这个过程中,前台会继续执行ajax块后面的脚本,直到server端返回正确的结果才会去执行s ...
- 如何用js判断一个对象是不是Array
.如何用js判断一个对象是不是Array 1.Array.isArray(obj) 调用数组的isArray方法 2.obj instanceof Array 判断对象是否是Array的实例 3.Ob ...
- ehcache缓存框架之二级缓存
ehcache.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:x ...
- 三层交换机配置DHCP为不同VLAN分配IP地址
三层交换的原理以及DHCP的原理,作者在这里就不详细的解释了,在这里通过一个案例来了解使用三层交换做DHCP服务器,并为不同网段分配IP地址.在生产环境中,使用路由器或交换机做DHCP服务器要常见一些 ...
- LLDB奇巧淫技
打印视图层级 这个相信很多人都会了,是ta是ta就是ta recursiveDescription 用法大概就是如下 123 po [self.view recursiveDescription] p ...
- Janet Wu price
上次也是第一次参加百公里是2012的时候,那年的主题是一路有你,和一群同事从深圳湾走到福田,最后累了就回家了,那晚应该是睡得很好吧. 今年是提前报名了,虽然还不确定是否参加.因为说实话,我不喜欢拥堵的 ...
- MDEV入门
------------- MDEV入门------------- 对于我们这些人知道如何使用的mdev ,底漆可能似乎跛.为其他人的mdev是一个神秘的黑匣子,他们听到的是真棒,但不能似乎得到他们的 ...