| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> PHP知识库 -> Mybatis的一级、二级缓存 -> 正文阅读 |
|
[PHP知识库]Mybatis的一级、二级缓存 |
相关内容总结说明:
mybatis默认开启一级缓存,同一个sqlSession多次查询同一个namespace+id时,只会第一次查询数据库,后面的查询将直接从一级缓存中读取。
?
当执行sqlSession.commit()时,会刷新一级缓存,也就是清空一级缓存,如果此时开启了二级缓存,则会将一级缓存的结果写入二级缓存中保存。
?
mybatis的二级缓存需要设置才能开启。首先需要在mybatis-config.xml的settings标签中添加
<
setting
name
=
"cacheEnabled"
value
=
"true"
/>。
然后在需要开启二级缓存的sqlmapper文件(如HeroMapper.xml文件)中加上?
<
cache
></
cache
>?或?
<
cache/>.
并且对应的Hero对象需要继承Serializable(表示将对应的对象从内存写入硬盘)
mybatis的二级缓存写入时刻有:
1)sqlSession.commit();?清空一级缓存,如果开启了二级缓存,则
可能会将一级缓存的内容写入二级缓存(
如果commit前都是查询操作,则写入二级缓存,如果存在增删改操作,再commit,则清空二级缓存)。
注意:若当前某个sqlSession只进行了一系列查询,然后执行commit(),就将其对应的一级缓存内容写入二级缓存中。所以二级缓存存放的可以能多个sqlSession对象的一级缓存写入的内容。
但如果此时
任一个sqlSession进行了增删改操作后,再执行commit(),则会
清空二级缓存。此时
所有对应的sqlSession对象查询时,都不会命中。
二级缓存清空后,所有的sqlSession的查询会从头开始,即如果只是sqlSession查询,不commit()也不close(),第一次从数据库查询,二次及以上查询将从一级缓存中返回数据。
?
2)sqlSession.close();? 这个方式主要是在多个sqlSession对象访问同一个mapper接口时用到。比如?sqlSession1?访问?HeroMapper.class?并进行了查询操作,然后执行 sqlSession1.close(),就会将sqlSession1?查到的数据写入二级缓存中 ,SqlSession2?如果访问?HeroMapper.class?进行了相同的查询操作,就可以访问到?sqlSession1?之前查过的缓存数据了。
注意:sqlSession1.close()之后,sqlSession1?就不可以再用来查询数据了,所以访问二级缓存的数据时,不可能是当前的sqlSession执行close()之后,再次查询数据,都是查的其他的sqlSession对应写入到二级缓存的数据。
mybatis开启二级缓存后,查询一级缓存、二级缓存、数据库的先后顺序是: 二级缓存 ——》 一级缓存 ——》 数据库 说明:可能大家都会觉得应该是先 一级缓存,再二级缓存,最后数据库。但其实际查询的先后顺序从控制台日志就可以看出来。 每次查询结果前,不管是否输出的SQL(即查询数据库),首先展示的都是命中率,而命中率是相对二级缓存是否可以查到数据而言的,这就说明了,每次数据查询,最先查询的都是二级缓存。 没有写入二级缓存,执行二次及以上次查询时,显示命中率是0,但不输出查询SQL,这说明结果是从一级缓存中返回的,也就是先在二级缓存中查了,没查到,然后去一级缓存中查,查到了,返回。 在上面说到二级缓存写入时刻时,对commit()重点进行了说明,如果某个sqlSession进行了增删改操作,然后commit(),会清空二级缓存;但如果没有哪个sqlSession进行增删改操作,或者一直不commit(),则会一直命中。这个时候的命中率的提升,说明当二级缓存中有数据时,结果将直接从二级缓存中返回,因为如果sqlSession查询不commit(),按道理是会将结果写入一级缓存的,但此时命中率一直升高,而且不输出SQL,只能说明是先查的二级缓存。二级缓存中有数据时,多次查询是否了写入一级缓存,估计是没有。 所以 顺序是:二级缓存 ——》 一级缓存 ——》 数据库
具体说明:
1.一级缓存
? ??1) mybatis默认开启一级缓存
? ? 2)一级缓存是相对于
同一个 SqlSession?而言的,用同一个SqlSession查询查询同样的数据,只会执行一次SQL,因为使用SqlSession第一次查询后,mybatis会将结果放到SqlSession中。除非使用SqlSession.commit() 。
? ? 3)SqlSession.commit()会刷新一级缓存。sqlsession.close()也会清空一级缓存。
? ? 4)与执行select不同的是,执行update,insert,delect操作后会清空一级缓存中的数据,而不是通过算法生成缓存的键值存入一级缓存,之所以有这种差别是因为 select的flushCache(清空缓存)默认为false,而update,insert,delect的flushCache(清空缓存)默认为true。
如果Mybatis-config.xml文件中的TransactionManage的 type 是
?JDBC?类型,则需要手动?commit。
?? ??? ??? ?<
environment
id=
"development1"
>
??????????????
<
transactionManager
type=
"JDBC"
></
transactionManager
>
??????????????
<
dataSource
type=
"POOLED"
>
??????????????????
<
property
name=
"driver"
value=
"${how2java.driver}"
/>
??????????????????
<
property
name=
"url"?
value=
"${how2java.url}"
/>
??????????????????
<
property
name=
"username"
value=
"${how2java.username}"
/>
??????????????????
<
property
name=
"password"
value=
"${how2java.password}"
/>
??????????????
</
dataSource
>
?????????
</
environment
>
? ? 5)在Java代码中,增删改操作后,有时不调用sqlSession.commit(),发现查到的数据也已经更新。但实际在数据库中查询数据,却发现没有更新。
?? ?
?? ?原因是因为这个原因是因为mybatis默认不是自动提交事务的, 所以其实没有修改数据库,刚刚更新完后立即返回的结果,
是从mybatis为了提高性能设置的缓存里读取的,不是从数据库读取的。
解决的办法:一是在openSession() 的括号里写true, 设定自动提交事务, 一是在代码中加入
sqlSession.commit()
————————————————
版权声明:本文为CSDN博主「陈君豪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
???????? ??? ? SqlSession
sqlSession2? =
sessionFactory.openSession();
??????????????? HeroMapper
heroMapper =
sqlSession2.getMapper(HeroMapper.
class);
??????????????? Hero
hero4 =
heroMapper.selectHeroById(3);
??????????????? System.
out.println(
hero4);
???????????????
??????????????? Hero
hero =
new Hero();
???????????????
hero.setId(3);
???????????????
hero.setName(
"test");
???????????????
hero.setHp(22.4);
???????????????
hero.setDamage(33);
???????????????
heroMapper.updateHeroById(
hero);
???????????????
??????????????? Hero
hero2 =
heroMapper.selectHeroById(3);
??????????????? System.
out.println(
hero2);
?? ?在这个代码操作中,更新ID=3的Hero对象后,不对sqlSession进行提交,虽然?控制台?中打印的结果看,hero2? 已经?在 hero4?的基础上更新了,但实际在数据库中查询的还是?hero4?的数据。
? ? 从控制台输出也可以看出:
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 396283472.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@179ece50]
DEBUG [main] - ==>? Preparing: select id,name,hp,damage from hero where id = ??
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - <==????? Total: 1
id:3,name:小先,hp:27.0,damage:100.0? ? ?
【hero4对象】
DEBUG [main] - ==>? Preparing: update hero set name=?,hp=?,damage=? where id =??
DEBUG [main] - ==> Parameters: test(String), 22.4(Double), 33.0(Double), 3(Integer)
DEBUG [main] - <==??? Updates: 1
DEBUG [main] - ==>? Preparing: select id,name,hp,damage from hero where id = ??
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - <==????? Total: 1
id:3,name:test,hp:22.4,damage:33.0
? ? ?【hero2对象,输出的是更新后的数据】
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4135c3b]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4135c3b]
DEBUG [main] - Returned connection 68377659 to pool.
DEBUG [main] - Rolling back JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@179ece50]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@179ece50]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@179ece50]
DEBUG [main] - Returned connect
ion 396283472 to pool.
?? ??
? 【因为transactionManage的type类型是JDBC,mybatis不会自动commit,hero2只是从缓存中读取的,最终因为没有手动commit,所以在断开connection前,进行了rollback 】
?? ?? ? 如果希望更新的数据写入数据库,有两种方式:
? ? ?? ?1)SqlSession
sqlSession2? =
sessionFactory.openSession(true);
? ? 该方式会将增删改后的数据写入数据库,但不会清空二级缓存。
? ? 2)更新操作后进行?
sqlSession2.commit();?即,将上面代码的注释放开
? ? 该方式会将增删改后的数据?写入数据库,同时清空二级缓存。
2.二级缓存
?? ?
Mybatis
的二级缓存是指mapper映射文件。二级缓存的作用域是
同一个namespace
下的mapper
映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,并且执行了
sqlSession.commit(),则该SQLSession对应的mapper映射文件的二级缓存会被清空。
? ? 示例:
?? ??? ??? ???Reader
rs = Resources.
getResourceAsReader(
"mybatis-config.xml");
??????????????? SqlSessionFactory
sessionFactory =
new SqlSessionFactoryBuilder().build(
rs);
???????????????
??????????????? SqlSession
sqlSession1? =
sessionFactory.openSession();
???????????????
???????????????
// sqlsession的两种使用方式:
???????????????
//a.实例操作 参数:SQLMapper映射文件里面要调用的ID
??????????????? String
statement =
"com.how2jave.mybatis_demo.mapper.HeroMapper.selectHeroById";
??????????????? Hero
hero1 =
sqlSession1.selectOne(
statement,3);
??????????????? System.
out.
println(
hero1);?? ?? ? ? ? ? ??
?? ??? ??? ??? ?HeroMapper
heroMapper1 =
sqlSession1.getMapper(HeroMapper.
class);
??????????????? Hero
hero3 =
heroMapper1.selectHeroById(3);
???????????????
sqlSession1.close();? //关闭sqlSession1后,会将sqlSession1的一级缓存内容写入HeroMapper.class对应的二级缓存中
???????????????
???????????????
//b.基于mapper接口的操作
??????????????? SqlSession
sqlSession2? =
sessionFactory.openSession(
true);? ?//使用方式1将更新的数据写入数据库,该方式不会清空二级缓存
??????????????? HeroMapper
heroMapper =
sqlSession2.getMapper(HeroMapper.
class);
??????????????? Hero
hero =
new Hero();
???????????????
hero.setId(3);
???????????????
hero.setName(
"test");
???????????????
hero.setHp(22.4);
???????????????
hero.setDamage(33);
???????????????
heroMapper.updateHeroById(
hero);
???????????????
??????????????? Hero
hero2 =
heroMapper.selectHeroById(3);
??????????????? Hero
hero6 =
heroMapper.selectHeroById(3);
??????????????? Hero
hero7 =
heroMapper.selectHeroById(3);
??????????????? Hero
hero8 =
heroMapper.selectHeroById(3);
?? ?
console的信息如下:
DEBUG [main] - Cache Hit Ratio [com.how2jave.mybatis_demo.mapper.HeroMapper]:
0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1427646530.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55182842]
DEBUG [main] - ==>? Preparing: select id,name,hp,damage from hero where id = ??
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - <==????? Total: 1
id:3,name:小先,hp:27.0,damage:100.0
DEBUG [main] - Cache Hit Ratio [com.how2jave.mybatis_demo.mapper.HeroMapper]:
0.0
id:3,name:小先,hp:27.0,damage:100.0? ?
【sqlSession1的一级缓存,没有查询数据库,直接从一级缓存中获取了数据】
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55182842]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55182842]
DEBUG [main] - Returned connection 1427646530 to pool.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Checked out connection 1427646530 from pool.
DEBUG [main] - ==>? Preparing: update hero set name=?,hp=?,damage=? where id =??
DEBUG [main] - ==> Parameters: test(String), 22.4(Double), 33.0(Double), 3(Integer)
DEBUG [main] - <==??? Updates: 1? ?
【
sqlSession2
? =
sessionFactory
.openSession(
true
),将更新的数据写入了数据库,在?Navicat中查到了更新后的数据
】
DEBUG [main] - Cache Hit Ratio [com.how2jave.mybatis_demo.mapper.HeroMapper]:
0.3333333333333333
DEBUG [main] - ==>? Preparing: select id,name,hp,damage from hero where id = ??
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - <==????? Total: 1?? ?? ?【sqlSession2的二级缓存查询,】
DEBUG [main] - Cache Hit Ratio [com.how2jave.mybatis_demo.mapper.HeroMapper]:
0.5
DEBUG [main] - Cache Hit Ratio [com.how2jave.mybatis_demo.mapper.HeroMapper]:
0.6
DEBUG [main] - Cache Hit Ratio [com.how2jave.mybatis_demo.mapper.HeroMapper]:
0.6666666666666666
id:3,name:test,hp:22.4,damage:33.0
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55182842]
DEBUG [main] - Returned connection 1427646530 to pool.
二级缓存中多个sqlSession执行commit或close方法示例:
??? ??? ??? ??? ?String
statement =
"com.how2jave.mybatis_demo.mapper.HeroMapper.selectHeroById";
??????????????? Hero
hero1 =
sqlSession1.selectOne(
statement,3);
??????????????? System.
out.println(
hero1);
???????????????
???????????????
??????????????? HeroMapper
heroMapper1 =
sqlSession1.getMapper(HeroMapper.
class);
???????????????
sqlSession1.commit();??
//此处执行commit和close都会将sqlSession1中的查询写入mybatis的二级缓存中
//????????????? sqlSession1.close();
???????????????
???????????????
//b.基于mapper接口的操作
??????????????? SqlSession
sqlSession2? =
sessionFactory.openSession(
true);
??????????????? HeroMapper
heroMapper =
sqlSession2.getMapper(HeroMapper.
class);
???????????????
??????????????? SqlSession
sqlSession3? =
sessionFactory.openSession(
true);
??????????????? HeroMapper
heroMapper3 =
sqlSession3.getMapper(HeroMapper.
class);
??????????????? Hero
hero2 =
heroMapper.selectHeroById(3);
???????????????
??????????????? Hero
hero =
new Hero();
???????????????
hero.setId(3);
???????????????
hero.setName(
"test");
???????????????
hero.setHp(22.4);
???????????????
hero.setDamage(33);
???????????????
heroMapper.updateHeroById(
hero);
//????????????? sqlSession2.commit();
//若上面不执行update操作,只是commit,则不会清空mybatis二级缓存中
"
com.how2jave.mybatis_demo.mapper.HeroMapper.selectHeroById",3?
的查询结果,
但如果
先执行上面的update操作,然后再执行commit,会将mybatis二级缓存中对应的数据清空
,下面的查询都不会命中。
也就是说,
commit操作后,
如果mybatis二级缓存中发现有数据更新了,不会把更新的数据写入二级缓存中,而是直接将这部分数据删除
。
但是如果update操作不是用
sqlSession2.commit
()将数据写入的数据库,而是使用?
SqlSession
sqlSession2
? =
sessionFactory
.openSession(
true
);?并将
sqlSession2.commit
()注释掉,则数据库写入操作成功,且mybatis二级缓存会命中(命中率增加)。
但只有当前的sqlSession2才能查到最新的数据,其他的sqlSession查到的都是更新前的数据。如下面的 hero3 、hero9?都是数据更新前的数据。
??????????????
??????????????? Hero
hero6 =
heroMapper.selectHeroById(3);
??????????????? Hero
hero7 =
heroMapper.selectHeroById(3);
??????????????? Hero
hero8 =
heroMapper.selectHeroById(3);
??????????????? System.
out.println(
hero8);
??????????????? Hero
hero3 =
heroMapper1.selectHeroById(3);
??????????????? System.
out.println(
hero3);
???????????????
??????????????? Hero
hero9 =
heroMapper3.selectHeroById(3);
??????????????? System.
out.println(
hero9);
???????????????
sqlSession2.close();
|
|
PHP知识库 最新文章 |
Laravel 下实现 Google 2fa 验证 |
UUCTF WP |
DASCTF10月 web |
XAMPP任意命令执行提升权限漏洞(CVE-2020- |
[GYCTF2020]Easyphp |
iwebsec靶场 代码执行关卡通关笔记 |
多个线程同步执行,多个线程依次执行,多个 |
php 没事记录下常用方法 (TP5.1) |
php之jwt |
2021-09-18 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/29 5:27:00- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |