MyBatis 缓 存

本文详细解析了MyBatis的一级缓存和二级缓存机制。介绍了一级缓存如何在同一个SqlSession中减少重复数据库查询,以及二级缓存如何在多个SqlSession间共享数据。还探讨了缓存配置及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MyBatis 缓 存

一.缓存

1.应用程序和数据库交互的过程是一个相比较耗时的过程。

2.缓存存在意义:让应用程序减少对数据库的访问,提升程序运行效率。

3.缓存是基于查询之上的。MyBatis中分一级缓存(SqlSession缓存)和二级缓存(SqlSessionFactory缓存)。

二.SqlSession缓存

1.MyBatis中SqlSession缓存是默认开启的。缓存的是statement对象。在mybatis.xml中一个< select >对应一个statement对象

2.执行sql语句时缓存流程:

(1) 先去缓存区中找是否存在statement

(2) 返回结果

(3) 如果没有缓存statement对象,则去数据库中获取数据

(4) 数据库返回查询结果

(5) 把查询结果放到对应的缓存区中
[外链图片转存失败(img-la2sel7w-1563867673477)(https://i.imgur.com/VkySvPb.png)]

3.同一SqlSession对象调用同一 < select > 时,只有第一次访问数据库,第一次之后把查询结果缓存到SqlSession缓存区(内存)中。

代码示例:

public static void main(String[] args) throws IOException {

InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
  
session.selectList("com.tit.mapper.LogMapper.selAll");
session.selectList("com.tit.mapper.LogMapper.selAll");
}

执行的sql:

`org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.0 
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==>  Preparing: select * from log  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==> Parameters:  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG <==      Total: 16 
org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.0`

注:同一SqlSession对象调用相同的< select >,只产生一个stetement对象。

4.缓存的是statement对象。在mybatis.xml中一个< select >对应一个statement对象。

代码示例:

      public static void main(String[] args) throws IOException {	InputStream is =           Resources.getResourceAsStream("mybatis.xml");
	SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
	SqlSession session = factory.openSession();  
	session.selectList("com.tit.mapper.LogMapper.selAll");
	session.selectList("com.tit.mapper.LogMapper.selAllTO");
  }

mapper.xml中:

< mapper namespace=“com.tit.mapper.LogMapper” >

< select id=“selAll” resultType=“log” >
​ select * from log
< /select>

< select id=“selAllTO” resultType=“log”>
​ select * from log
< /select>

< /mapper>

执行的sql:

`org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.0 
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==>  Preparing: select * from log  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==> Parameters:  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG <==      Total: 16 
org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.0 
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==>  Preparing: select * from log  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==> Parameters:  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG <==      Total: 16 `

注:同一SqlSession对象调用不同的< select >,产生两个stetement对象。

三.SqlSessionFactory缓存

1.实现多个SqlSession对象共享数据(session.close()后,SqlSession缓存的内容刷到SqlSessionFactory中)。

2.当数据频繁被使用,却很少被修改时,才使用SqlSessionFactory缓存,否则会读取到脏数据。

3.使用步骤:在mapper.xml中添加 < cache readOnly=“true”>< /cache>

其中readOnly=“true” 表示是否对二级缓存数据进行读取。若不加readOnly=“true”,则将所有实体类序列化也可开启二级缓存。
注:序列化与反序列化:

[外链图片转存失败(img-WQgH3dTa-1563867673480)(https://i.imgur.com/LmXKRtH.png)]

一个类序列化之后,类中所有数据就允许从临时数据保存至硬盘上。

4.代码示例:

不同SqlSession对象调用同一 < select> :

`public static void main(String[] args) throws IOException {	InputStream is = Resources.getResourceAsStream("mybatis.xml");
	SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
	SqlSession session = factory.openSession();
	
	SqlSession session = factory.openSession();
	session.selectList("com.tit.mapper.LogMapper.selAll");
	session.close(); 
	
	SqlSession session1 = factory.openSession();
	session1.selectList("com.tit.mapper.LogMapper.selAll");
	session1 .close(); 
	
}`

mapper.xml中:

`< mapper namespace="com.tit.mapper.LogMapper" >
  < cache readOnly="true">< /cache> 

 < select id="selAll" resultType="log" statementType="PREPARED">
​     select * from log 
 </ select>
 < select id="selAllTO" resultType="log">
​     select * from log 
 < /select>

< /mapper>`

执行的sql:

`org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.0 
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==>  Preparing: select * from log  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==> Parameters:  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG <==      Total: 16 
org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.5`

四.一级缓存和二级缓存

1.当Sqlsession对象commit()或close()时,会把Sqlsession缓存的数据刷(flush)到SqlSessionFactory的缓存区中。

2.将上面代码修改如下:
​ 将session.close();注释

`public static void main(String[] args) throws IOException {	InputStream is = Resources.getResourceAsStream("mybatis.xml");
	SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
	SqlSession session = factory.openSession();
	session.selectList("com.tit.mapper.LogMapper.selAll");
	//session.close(); 
	
	SqlSession session1 = factory.openSession();
	session1.selectList("com.tit.mapper.LogMapper.selAll");
	session1 .close(); 
	
}`

mapper.xml不变,执行的sql:

`org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.0 
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==>  Preparing: select * from log  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG ==> Parameters:  
org.apache.ibatis.logging.jdbc.BaseJdbcLogger DEBUG <==      Total: 16 
org.apache.ibatis.cache.decorators.LoggingCache DEBUG Cache Hit Ratio [com.tit.mapper.LogMapper]: 0.5 `

3.流程图:
[外链图片转存失败(img-6khfBzWg-1563867673481)(https://i.imgur.com/Aya2Pfr.png)]

注:将session.close();注释后,SqlSession缓存的内容并没有刷到SqlSessionFactory中,所以产生两个statement对象。

五.补充

statementType=“CALLABLE”

​ “PREPARED” -默认值

​ “STATEMENT”

statement:执行sql的执行器

CALLABLE:JDBC中执行存储过程的执行器

PREPARED:PREPARED接口是接口STATEMENT的子接口,解决了STATEMENT的sql注入问题。

2.Connection conn=null;

conn.prepareStatement("");

conn.createStatement("");

 "STATEMENT"

statement:执行sql的执行器

CALLABLE:JDBC中执行存储过程的执行器

PREPARED:PREPARED接口是接口STATEMENT的子接口,解决了STATEMENT的sql注入问题。

2.Connection conn=null;

conn.prepareStatement("");

conn.createStatement("");

conn.prepareCall("");//调用存储过程的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值