-
2021-12-09 10:58:28更多相关内容
-
mybatis的一级缓存和二级缓存
2022-04-14 17:29:43在分布式的环境中,mybatis的一二级缓存非常危险,二级缓存一定要关闭,一级缓存视情况关闭 一级缓存失效的四种情况: sqlSession不同。 sqlSession相同,查询条件不同。因为缓存条件不同,缓存中还没有数据。 sq一级缓存
1、说明
mybatis默认开启一级缓存,一级缓存的作用域是
SqlSession
范围的,当在同一个sqlSession
中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。在分布式的环境中,mybatis的一二级缓存非常危险,二级缓存一定要关闭,一级缓存视情况关闭
一级缓存失效的四种情况:
- sqlSession不同。
- sqlSession相同,查询条件不同。因为缓存条件不同,缓存中还没有数据。
- sqlSession相同,在两次相同查询条件中间执行过增删改操作。(因为中间的增删改可能对缓存中数据进行修改,所以不能用)
- sqlSession相同,手动清空了一级缓存。
2、关闭方法
(1)注解形式
使用注解
@Options(flushCache = Options.FlushCachePolicy.TRUE)
可指定仅仅某个Mapper关闭注解)@Options(flushCache = Options.FlushCachePolicy.TRUE) @Select("select * from ge_jdbc_datasource where id = #{id,jdbcType=BIGINT} and status = 1") @ResultMap("resultMap") JdbcDataSource find(Long id);
(2)传入随机数
比如sql传参random()数值 或者 sql传入当前时间毫秒数,切记一定要从方法形参传过去而不要在sql中拼写,否则无效
举例说明:下面方式无效
select id from ge_jdbc_datasource where id = 1 and STATUS = 1 AND NOW()=NOW()
(3)设置 statementType
在
mapper
的select
标签中设置statementType=STATEMENT
statementType
的设置有3种:STATEMENT
:直接操作sql,不进行预编译,获取数据PREPARED
:(默认)预处理,参数,进行预编译,获取数据CALLABLE
:执行存储过程————CallableStatement
(4)设置 flushCache
在
mapper
的select
标签中设置flushCache=“true”
(5)设置 localCacheScope
全局设置
localCacheScope=STATEMENT
参考:https://blog.csdn.net/u011649691/article/details/116058056
2、案例
我们在
getPaymentById
方法中写了两次查询,并且保证方法内的sqlSession
是同一个。在两次查询期间对数据进行修改,将serial=001
修改为serial=002
。package com.scy.springcloud.service.impl; import com.scy.springcloud.dao.PaymentDao; import com.scy.springcloud.entities.Payment; import com.scy.springcloud.service.PaymentService; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.List; @Service public class PaymentServiceImpl implements PaymentService { @Resource private PaymentDao paymentDao; //这里注入的sqlSession是org.mybatis.spring.SqlSessionTemplate /*@Resource public SqlSession sqlSession;*/ @Resource SqlSessionFactory sqlSessionFactory; @Override public Payment getPaymentById2(Long id) { //org.apache.ibatis.session.defaults.DefaultSqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); Payment payment = sqlSession.selectOne("getPaymentById", id); System.out.println(payment.toString()); try { Thread.sleep(10*1000); } catch (InterruptedException e) { e.printStackTrace(); } Payment payment2 = sqlSession.selectOne("getPaymentById", id); System.out.println(payment2.toString()); sqlSession.close(); return payment2; } }
查询1(开启缓存)
两次查询是同样的,没有改变,说明开启了一级缓存。
Payment(id=31, serial=001) Payment(id=31, serial=001)
查询2(关闭缓存)
在
select
标签中加入flushCache="true"
后,使一级缓存失效。<select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap" flushCache="true"> select * from payment where id = #{id}; </select>
第二次查询结果变为serial=002,说明一级缓存失效。
Payment(id=31, serial=001) Payment(id=31, serial=002)
二级缓存
1、说明
MyBatis
的二级缓存是Application级别的缓存,二级缓存的作用域默认为mapper(namespace)
工作机制:
-
一个会话,查询一条数据,这个数据会被放在当前会话的一级缓存中。
-
如果会话被关闭了,一级缓存中的数据会被保存到二级缓存。新的会话查询信息就会参照二级缓存。
-
sqlSession > Employee>employee
sqlSession >DepartmentMapper=>Department
不同的namespace查出的数据会放在自己对应的缓存中。
效果:
查出的数据首先放在一级缓存中,只有一级缓存被关闭或者提交以后,一级缓存数据才会转移到二级缓存
2、开启方法
(1)方式一
在
mybatis
的配置文件中进行配置<configuration> <settings> <!-- 二级缓存开启 --> <setting name="cacheEnabled" value="true"/> </settings> </configuration>
(2)方式二
在
application.yml
文件中进行配置开启mybatis的二级缓存mybatis.configuration.cache-enabled=true
# 开启二级缓存 mybatis: configuration: cache-enabled: true # 开启sql打印(可以方便查看是否使用了缓存) logging: level: com.scy.springcloud.dao: debug
3、开启缓存配置
开启二级缓存的分开关。
要加入cache的配置二级缓存才会开启。
<mapper namespace="com.scy.springcloud.dao.PaymentDao"> <!-- 开启二级缓存 --> <cache eviction="LRU" flushInterval="20000" readOnly="true" size="1024"> </cache> </mapper>
cache 相关属性:
-
eviction
: 缓存的回收策略LRU
(默认):最近最少使用,移除最长时间不被使用的对象FIFO
:先进先出,安对象进入缓存的顺序来移除它们SOFT
:软引用,移除基于垃圾回收器的状态和软引用规则的对象WEAK
: 弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象
-
flushInterval
:缓存刷新间隔 缓存多长时间清空一次,默认不清空,设置一个毫秒值 -
readOnly
:是否只读 。true
:只读,mybatis
认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。mybatis
为了加快获取速度,直接会将数据在缓存中的引用交给用户,不安全,但速度快。false
:非只读,mybatis
觉得获取的数据可能会被修改。会利用序列化&反序列化的技术克隆一份新的数据给你,安全,但速度慢。
-
size
:缓存最多存放多少个引用。默认1024。 -
type
:指定自定义缓存的全类名,实现Mybatis
提供的Cache
接口即可。
注意事项:
实体对象要
implements Serializable
,否则报错public class User implements Serializable{ }
启动工程,如果出现
Cache Hit Ratio . # 表示缓存开启了.....
参考:
Mybatis二级缓存失效及二级缓存使用简介
https://blog.csdn.net/sao_jie/article/details/119297811浅谈一下mybatis中@CacheNamespace和@CacheNamespaceRef的区别以及使用
https://blog.csdn.net/lovely960823/article/details/111277801
-
#Mybatis 关于mybatis的一级缓存
2022-03-19 17:39:28mybatis一级缓存分析# 本篇文章主要是为了帮助自己总结和加深理解,若能帮助到其他小伙伴也是极好的
基本介绍
Mybatis中支持一级缓存和二级缓存,一级缓存是默认开启的并且不能关闭,二级缓存默认关闭,可根据需要进行手动开启,总体来说Mybatis的一二级缓存的最终目的就是为了帮助数据库减轻压力,保证高效高速的查询,提高数据库的瓶颈。
一级缓存
一级缓存是基于hashmap的本地缓存,作用域只在session中,当session刷新或关闭后,这个session中所有的cache就会被清空。
注意 如果使用clearCache以及增、删、改的sql进行操作会导致select缓存被清空。
命中原则
mybatis是怎样判断两次select语句是完全相同的查询sql?
1、statementId
statementId其实就是select语句标签中的的id,如果两条select的id不同,那么必定不会命中。
例如图中代码,这是两条相同的select查询语句,先使用getByName01进行查询,再使用getByName02以及相同的参数进行查询,仍然不会进入缓存。
<select id="getByName01"> SELECT * FROM `user` WHERE name=#{name} <select/> <select id="getByName02"> SELECT * FROM `user` WHERE name=#{name} <select/>
2、查询参数
若两次查询必须使用同一条statementId的sql,并且传入的参数一样,否则无法命中缓存。
这里要注意的是,mybatis不论你在java代码中使用何种方式进行传参,只要最终sql语句中获取的参数相等就可以判定为是相同的参数。
我们编写一条根据name查询的select,并且使用Map传参。
<select id="getByName" parameterType="java.util.Map" resultType="user"> SELECT * FROM `user` WHERE name=#{name} <select/>
在两次查询中,我们传入两个不同的hashmap参数(只有name会传入sql中),结果会怎样?第二次查询使用缓存还是查询数据库?
public void test(){ // 第一次查询 HashMap param1 = new HashMap(); param1.put("name","alix"); param1.put("test",123); mapper.getUserByName(param1); // 第二次查询 HashMap param2 = new HashMap(); param2.put("name","alix"); param1.put("test",321); mapper.getUserByName(param2); }
通过测试执行,第二次查询竟然没有去数据库查询,而是读取了第一次查询的缓存,通过查看sql日志我们发现sql编译的结果如图所示。
==>> Preparing:SELECT * FROM user WHERE name=?
==>>Parameters:alix(Integer)
<<== Total:1
所以,参数相同指的是最终传递到sql中的参数只要是一样的就可以满足条件。
3、分页参数
这里的分页指的是mybatis自带的分页功能,很多人可能不熟悉或者很少使用,因为它是查询出数据库的所有数据到本地进行一个物理分页,而不是直接从数据库获取分页之后的结果,这样的一个操作执行效率很低,非常损耗性能,所以也不推荐使用(这里不做过多说明)。
4、sql语句
顾名思义,mybatis要求我们查询时使用的sql语句必须相同。但值得注意的是,这里所说的sql语句必须相同指的是这条语句加上参数最终拼接形成完整的sql文本必须完全一样。
也就是说在查询时并不会考虑sql语句本身的语义,如下代码所示。
<select id="getUserByNameInGender"> <if test="gender == 0"> SELECT * FROM user WHERE name=#{name} </if> <if test="gender == 1"> SELECT * FROM user WHERE 1=1 AND name=#{name} </if> </select>
我们知道
SELECT * FROM user WHERE 1=1 AND name=#{name}和SELECT * FROM user WHERE name=#{name}
其实是两个意义完全相同的sql语句,但mybatis并不会考虑这种情况。
总结
mybatis的一级缓存在什么时候产生?在什么情况下销毁?
产生:
在使用select标签进行查询时才会产生缓存,如果我们在诸如update标签中使用select语句进行查询并不会产生缓存。
销毁:
一级缓存是维持在同一个sqlsession中的,因此在对sqlsession使用close关闭或commit提交后,缓存就会被清空;
在使用sqlsession.rollback()进行回滚时,也会导致缓存被清空;
进行update操作也会造成缓存被清空,并且dll语句对查询缓存的影响并不局限于同一张表,就是说在A表进行查询产生缓存,然后对B表进行dll操作同样会使A表的select缓存失效(并且是所有缓存);
sqlsession还提供了clearCache()方法,这个方法可以让我们主动的对缓存进行清空;
经常有提到说mybatis一级缓存可能导致脏读的情况,是否真实?为什么?怎么解决?
针对mybatis一级缓存可能存在产生脏读的情况,我们可以模拟并发情况下的执行步骤来进行分析;
如果按照图中步骤来看,mybatis一级缓存的确存在可能造成脏读的情况;
所以在实际开发环境中应该避免使用mybatis缓存,而是使用类似redis这样的第三方插件进行全局缓存的管理;
补充
一级缓存的hashmap中key和value分别存的是?
key:hashcode值 + sqlId + sql语句;
value:映射结果对象;
后言
你好,很高兴认识你
本次关于 “ mybatis一级缓存 ” 的文章到此完结,若有疑问可以私信与我交流。
如果你也喜欢编程,如果你也喜欢敲代码,如果你也喜欢技术,欢迎联系~
我是
爱敲代码的小王bro
-
mybatis一级缓存和二级缓存彻底关闭
2021-11-23 00:36:55在mybatis-coinfig.xml文件添加如下配置: <configuration> <settings> <!...-- 设置一级缓存的作用范围是一条sql语句执行期间,执行完毕清空一级缓存--> <setting name=在mybatis-coinfig.xml文件添加如下配置:
<configuration> <settings> <!-- 关闭二级缓存--> <setting name="cacheEnabled" value="false"/> <!-- 设置一级缓存的作用范围是一条sql语句执行期间,执行完毕清空一级缓存--> <setting name="localCacheScope" value="STATEMENT"/> </settings> </configuration>
关闭二级缓存,设定一级缓存作用范围之后,可以彻底解决mybatis数据脏读问题。
一级缓存不能彻底关闭,因为mybatis内部的许多功能都是基于一级缓存实现的。
-
MyBatis 的一级缓存与二级缓存
2022-02-11 15:12:02MyBatis 的一级缓存是基于数据库会话(SqlSession 对象)的,默认开启。二级缓存是基于全局(nameSpace)的,开启需要配置。 对于 JDBC 操作,如果需要连续请求 id=1 的用户数据,那么就要进行两次的数据库连接,获取... -
Mybatis 禁用一级缓存
2021-07-26 16:33:09一张数据库中的表:table_name,这张表在开发的过程中对应两个Mapper(比如两个模块:模块a, 模块b),mybatis 默认是开启一级缓存的。现在的情况是我在模块a中用程序修改了table_name中的某个字段值(比如:field原来... -
mybatis一二级缓存和如何关闭
2021-04-23 15:26:45Mybatis默认开启一级缓存。 关闭或者使一级缓存失效的方法: 1、在mapper的select标签中设置statementType=STATEMENT statementType的设置有3种: STATEMENT:直接操作sql,不进行预编译,获取数据 PREPARED:(默认... -
研究一天,终于把MyBatis的一级缓存和二级缓存搞清楚了
2021-12-21 11:16:51一级缓的作用域是 session(会话),二级缓存是 mapper 级别的缓存,二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享。 -
mybatis一级缓存,二级缓存的开启、关闭、清除及使用说明
2021-02-02 15:16:56Mybatis一级缓存(默认开启) 是SqlSession级别的缓存, 默认开启 Mybatis二级缓存(默认关闭,一般不建议使用) namspace/mapper级别(跨sqlSession)的缓存, 默认关闭 -
mybatis的一级缓存和二级缓存 -- 看完再也不懵逼
2021-05-30 18:21:40缓存是什么 缓存其实就是存储在内存中的临时数据,这里的数据量会比较小,一般来说,服务器的内存也是有限的,不可能将所有的数据都放到 -
Mybatis的一级缓存和二级缓存机制原理和区别
2022-01-19 16:05:00Mybatis中的一级缓存和二级缓存到底缓存了什么,缓存了以后又有什么效果,缓存的数据什么时候会被清空? 一级缓存:它指的是Mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入到... -
mybatis禁用一级缓存
2021-05-12 21:23:05localCacheScope默认值是SESSION,此时默认开启一级缓存。 值为statement,就会每次请求读取数据库,不会读缓存 -
Mybatis的一级缓存与二级缓存
2021-05-25 09:15:52Mybatis的一级缓存与二级缓存 缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存,我们可以避免频繁的与数据库 进行交互,进而提高响应速度。 Mybatis也提供了对缓存的支持,分为一级缓存和二级缓存... -
禁用 MyBatis 一级缓存
2022-04-08 22:03:57MyBatis 一级缓存默认开启,是 session 级别。如果要禁用一级缓存,就要设置为 statement 级别,即: <setting name="localCacheScope" value="SESSION"/> //STATEMENT mybatis: configuration: local-... -
mybatis的一级缓存详解
2020-12-28 15:44:58文章目录1、mybatis一级缓存是什么2、代码示例2.1.结果展示:2.2.现象解析3、有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据3.1代码如下:3.2结果:4、总结 1、mybatis一级缓存是什么 使用缓存可以... -
关于Mybatis关闭一级二级缓存
2018-09-10 15:29:24这两天折腾mybatis发现它的缓存内容比较不和谐,原因是底层架构会考虑到分布式,但是Mybatis的各个SqlSession的默认一级缓存PerpetualCache不会在各SqlSession间共享,同时他存储下来sql语句和查询到的对象集,再第二次... -
Mybatis的一级缓存失效、关闭一级缓存源码分析
2019-10-30 21:03:32Mybatis的一级缓存失效 在MyBatis和Spring整合中,存在MyBatis一级缓存失效的情况。 SqlSessionTemplate是SqlSession的默认实现,在SqlSessionTemplate的构造器中,创建了sqlSession的代理 //成员变量 private ... -
Mybatis-一级缓存
2022-04-05 16:54:01Mybatis默认开启一级缓存。 执行流程:当同一个会话中执行查询时,会先去缓存查找以该查询条件为键的值,如存在则缓存命中并返回结果,不存在则发送SQL语句给数据库查询。 增删改操作默认清空一级缓存和二级缓存。 ... -
Mybatis 的一级缓存和二级缓存详解
2021-07-31 17:15:59注:本笔记是根据尚硅谷的MyBatis视频记录的 ...关于Mybatis的一级缓存和二级缓存执行顺序具体可参考:Mybatis的一级缓存和二级缓存执行顺序 Mybatis整合第三方缓存步骤具体可参考:Myb... -
MyBatis如何关闭一级缓存(分注解和xml两种方式)
2021-06-16 17:00:55问题:为什么有缓存 mybatis默认开启一级缓存 什么场景下必须需要关闭一级缓存 ...关闭一级缓存方法(针对使用MyBatis场景) 第一种:xml形式(关闭所有一级缓存) <settings> <setting name="cacheEnable -
mybatis 一级缓存和二级缓存
2022-04-05 22:13:22配置mybatis maven: <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> &... -
mybatis中一级缓存
2018-10-19 00:36:11mybatis中提供有一级缓存 和 二级缓存,这里记录一下一级缓存 一级缓存(mybatis中默认开启) SqlSession级别的缓存,操作数据库时需要构造SQLSession对象, 在对象中有一个数据结构(HashMap)用于存储缓存数据,... -
谈谈Mybatis的一级缓存和二级缓存
2021-01-07 16:40:42Mybatis支持缓存,默认情况下是开启的一级缓存,一级缓存是SqlSession级别,缓存的是SqlSession对象。在SQL语句、参数都相同的情况下,我们使用同一个SqlSession对象调用同一个Mapper方法的时候,只需要执行一次SQL... -
Mybatis的一级缓存和二级缓存详解
2018-11-19 19:11:59注:本笔记是根据尚硅谷的MyBatis视频记录的 对于任何一个持久层框架,都有缓存机制;... 两个关于mybatis缓存额外的链接: ...关于Mybatis的一级缓存和二级缓存执行顺序具体可参考:Mybatis的一级缓存和二级缓存执行... -
Java面试题 (4) Mybatis中一级缓存 和 二级缓存的区别?
2022-04-04 12:07:53Java面试题 Mybatis中一级缓存 和 二级缓存的区别? 两者区别:一级缓存的作用域是在SqlSession中,二级缓存的作用域是针对mapper做缓存。 一级缓存(本地缓存): 一级缓存是框架默认为我们开启的,我们不需要做任何... -
MyBatis的一级缓存、二级缓存、EHCache及相关配置
2022-04-12 16:38:00MyBatis的缓存1.MyBatis的一级缓存2.MyBatis的二级缓存3.二级缓存的相关配置4.MyBatis缓存查询的顺序5.整合第三方缓存EHCache(了解)5.1添加依赖5.2.各个jar包的功能5.3.创建EHCache的配置文件ehcache.xml5.4.设置... -
MyBatis一级缓存和二级缓存
2022-03-12 17:20:16Mybatis 的一级缓存是指Session缓存。一级缓存的作用域默认是SqlSession。Mybatis默认开启一级缓存。 在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;第二次以后则直接去一级... -
Mybatis一级缓存
2022-03-20 16:35:50什么是缓存: ...Mybatis中的缓存:系统默认定义了两级缓存:一级缓存和二级缓存 - 默认情况下,只有一级缓存开启,(SqlSession级别的缓存,也称为本地缓存) - 二级缓存需要手动开启和配置,基