Mybatis - 一级缓存和二级缓存使用详解

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/J080624/article/details/55045614

【1】一级缓存是SqlSession级别的缓存

在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。

Mybatis默认开启一级缓存,存在内存中(本地缓存)不能被关闭,可以调用clearCache()来清空本地缓存,或者改变缓存的作用域。


【2】二级缓存是mapper级别的缓存

多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace。

不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

Mybatis默认没有开启二级缓存,需要在setting全局参数中配置开启二级缓存。

如果缓存中有数据就不用从数据库中获取,大大提高系统性能。


【3】一级缓存测试

默认作用域:session ;

	@Test
	public void testCacheOne(){
		/*set auto commit ,which equals to the above*/
		SqlSession session = MybatisUtils.getFactory().openSession(true);
		
		String statement = "com.web.mapper.userMapper.getUser";
		/*return the effect rows*/
		User user = session.selectOne(statement, 1);
		System.out.println("result.."+user);
//		session.clearCache();
		
		//测试缓存肯定针对同样的数据,如果id变为2,缓存里面没有。缓存测试无从谈起。
		user = session.selectOne(statement, 1);
		System.out.println("result.."+user);
		System.out.println("***************************************************");
	}

一级缓存默认开启,作用域为session

  • 缓存不清空时,连续查询:
	@Test
	public void testCacheOne(){
		/*set auto commit ,which equals to the above*/
		SqlSession session = MybatisUtils.getFactory().openSession(true);
		
		String statement = "com.web.mapper.userMapper.getUser";
		/*return the effect rows*/
		User user = session.selectOne(statement, 1);
		System.out.println("result.."+user);
//		session.clearCache();
		
		user = session.selectOne(statement, 1);
		System.out.println("result.."+user);
		System.out.println("***************************************************");
}

result as follows :

这里写图片描述

如上图所示,只进行了一次数据库查询。第二次查询的时候,默认使用了缓存。


  • 缓存清空,进行第二次查询:
@Test
public void testCacheOne(){
	/*set auto commit ,which equals to the above*/
	SqlSession session = MybatisUtils.getFactory().openSession(true);
	
	String statement = "com.web.mapper.userMapper.getUser";
	/*return the effect rows*/
	User user = session.selectOne(statement, 1);
	System.out.println("result.."+user);
	session.clearCache();
	
	user = session.selectOne(statement, 1);
	System.out.println("result.."+user);
	System.out.println("***************************************************");
}

result as follows :

这里写图片描述

如上图所示,两次都进行了数据库查询。


进行CUD操作,将默认清空缓存

....
...		
		session.update("com.web.mapper.userMapper.updateUser",new User(1, "mili", 21));
		session.commit();
		
		user = session.selectOne(statement, 1);
		System.out.println("result.."+user);
...
...

result as follows :

这里写图片描述

如上图所示,进行第三地查询时,将重新查询数据库。


同样,当session关闭时,即 session.close( ) ,将会清空缓存。

  • 当xml配置属性flushCache="true",也将不会使用缓存:
<!-- flushCache="true" useCache="false" -->
	 <select id="getUser" parameterType="int" resultMap="UserMap"  flushCache="true">
	 	select * from t_user where id=#{id}
	 </select>

result as follows :

这里写图片描述

综上,清空session缓存的六种方式 :

① session.clearCache( ) ;
② execute update(增删改) ;
③ session.close( );
④ xml配置 flushCache="true"
⑤ rollback;
⑥ commit。


【4】二级缓存测试

补充说明 userMapper.xml中启用二级缓存的简单方式:

<cache></cache>

对应源码如下:

public @interface CacheNamespace {
  Class<? extends org.apache.ibatis.cache.Cache> implementation() default PerpetualCache.class;

  Class<? extends org.apache.ibatis.cache.Cache> eviction() default LruCache.class;

  long flushInterval() default 0;

  int size() default 1024;

  boolean readWrite() default true;
  
  boolean blocking() default false;

  /**
   * Property values for a implementation object.
   * @since 3.4.2
   */
  Property[] properties() default {};
  
}

属性简单介绍如下:

1.映射语句文件中的所有select语句将会被缓存;

2.映射语句文件中的所有CUD操作将会刷新缓存;

3.缓存会默认使用LRU(Least Recently Used)算法来收回;

1.  LRU – 最近最少使用的:移除最长时间不被使用的对象。
2.  FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3.  SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4.  WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

4.缓存会根据指定的时间间隔来刷新(默认情况下没有刷新间隔,缓存仅仅调用语句时刷新);

5.缓存会存储列表集合或对象(无论查询方法返回什么),默认存储1024个对象。

6.缓存会被视为是read/write(可读/可写)的缓存,意味着检索对象不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。


实例如下 :

<mapper namespace="com.web.mapper.userMapper">

  • 开启二级缓存:
<mapper namespace="com.web.mapper.userMapper">
	
	<cache >
		<property name="eviction" value="LRU"/>//回收策略为LRU
		<property name="flushInterval" value="60000"/>//自动刷新时间间隔为60S
		<property name="size" value="1024"/>//最多缓存1024个引用对象
		<property name="readOnly" value="true"/>//只读
	</cache>
...
...	
  • 如果想在命名空间中共享相同的缓存配置和实例,可以使用cache-ref 元素来引用另外一个缓存。

如下所示:

<cache-ref namespace="com.web.mapper.userMapper" />
//引用userMapper 命名空间中的cache。

Tips:

① 默认作用域:Mapper(namespace) ;
② 实体类需要实现序列化接口Serializable ;
③ 确保数据写入二级缓存。


【Test1】

public void testCacheTwo(){
		SqlSessionFactory factory = MybatisUtils.getFactory();
		
		/*注意此处是从一个Factory 获取两个session*/
		SqlSession session1 = factory.openSession();
		SqlSession session2 = factory.openSession();
		
		String statement = "com.web.mapper.userMapper.getUser";
		/*return the effect rows*/
		User user = session1.selectOne(statement, 1);
		System.out.println("result.."+user);
		
		//进行提交或者关闭将其数据写入二级缓存,否则将不会写入二级缓存
//		session1.commit();
		session1.close();
		
		user = session2.selectOne(statement, 1);
		System.out.println("result.."+user);
//		session2.commit();
	}

result as follows :

这里写图片描述

当执行以下方式时,将不会写入二级缓存:

① session.clearCache();

② update();


【注意】:

如果两个session不是从同一个Factory获取,那么二级缓存将不起作用。

如下所示:

SqlSession sqlSession1 = MybatisUtils.getFactory().openSession();

SqlSession sqlSession2 = MybatisUtils.getFactory().openSession();
...
...

result as follows :

这里写图片描述

如图所示,两次都进行数据库查询。

命中率为0 !

Cache Hit Ratio [com.web.mapper.userMapper]: 0.0


【5】与Spring整合后MyBatis一级缓存默认失效(无事务存在时)

参考MyBatis-Spring整合文档说明如下:

Programmatic Transaction Management

MyBatis SqlSession provides you with specific methods to handle transactions programmatically. But when using MyBatis-Spring your beans will be injected with a Spring managed SqlSession or a Spring managed mapper. That means that Spring will always handle your transactions.

You cannot call SqlSession.commit(), SqlSession.rollback() or SqlSession.close() over a Spring managed SqlSession. If you try to do so, a UnsupportedOperationException exception will be thrown. Note these methods are not exposed in injected mapper classes.

Regardless of your JDBC connection’s autocommit setting, any execution of a SqlSession data method or any call to a mapper method outside a Spring transaction will be automatically committed.


MyBatis与Spring整合官网地址:http://www.mybatis.org/spring/transactions.html

MyBatis官网文档地址:http://www.mybatis.org/mybatis-3/

展开阅读全文

MyBatis一级缓存二级缓存

06-28

<p>n 本课程适合有JAVA和数据库基础的人员。n</p>n<p>n 本课程使用Eclipse和<span style="font-size:13.3333px;">IntelliJ IDEA两种开发工具,详细的讲解了MyBatis的各种语法,并且讲解了MyBatis逆向工程和MyBatis两种常用的插件:MyBatis Plus和通用Mapper。</span>n</p>n<p>n <span style="font-size:13.3333px;">本课程从理论和实际案例两方面充分讲解了MyBatis的各种技术细节,和应用场景,并且以绘图的方式讲解了各种MyBatis中较难的技术点。</span>n</p>n<p>n <span style="font-size:13.3333px;">相信可以通过本课程的学习,读者能够掌握MyBatis学习过程中的各种技巧和实际案例。</span>n</p>n<p>n <span style="font-size:13.3333px;">本课程中设计的大致技术点,如下所示。</span>n</p>n<p>n       1.Eclipse、IntelliJ IDEA环境下开发MyBatisn</p>n<span></span>      2.MyBatis多种方式的CRUD<br />n      3.MyBatis配置文件详解<br />n      4.MyBatis映射文件详解<br />n      5.使用MyBatis调用存储过程<br />n      6.动态SQL<br />n      7.关联查询<br />n      8.延迟加载<br />n      9.整合一级、二级缓存<br />n      10.逆向工程<br />n      11.事务操作<br />n      12.MyBatis处理多个参数的问题<br />n      13.鉴别器和别名<br />n      14.各种方式的模糊查询<br />n      15.MyBatis核心源码分析<br />n      16.MyBatis拦截器<br />n      17.MyBatis批量更新操作<br />n      18.PageHelper<br />n      19.MyBatis Plus详解<br />n      20.通用Mapper详解<br /><p>n    希望大家可以通过本课程的学习,深入的掌握MyBatis及其各种插件的用法,从而提高对数据的操作效率n</p>n<p>n <br /></p>

没有更多推荐了,返回首页