关于MyBatis中一级缓存的一些思考(二)

关于MyBatis中一级缓存的一些思考(二)

今天在继续学习关于Mybatis缓存知识的时候,了解到一些关于缓存有关的设置对一级缓存和二级缓存作用域的问题。大致上可以包含一些几条:
* 1.cacheEnabled=true/false(开启/关闭缓存,在全局配置文件的setting标签中设置):关闭了二级缓存,一级缓存一直可用;
* 2.useCache=“true”(默认为true):每个select标签都有这个属性,当值设置为false时表示不使用缓存(一级缓存依然使用,二级缓存被关闭(但是只针对这一条语句来说));
* 3.每个增删改标签都有一个属性:flushCache=“true”(默认为true):
(一级二级缓存都会清除)在select标签中也有flushCache属性,但是其默认为false,也就是在进行查询时默认不清空缓存;如果改为true,每次查询之前都会清空缓存(缓存没被使用),意思是增删改执行完以后就会清除缓存:测试结果flushCache=“true”:一级缓存被清空,二级缓存也会被清空;
* 4.sqlSession.clearCache():只是清除当前sqlSession的一级缓存;
* 5.localCacheScope:(本地缓存作用域,针对一级缓存)MyBatis使用本地缓存来防止循环引用并加速重复的嵌套查询。默认情况下(默认值是SESSION),在会话期间执行的所有查询都被缓存。如果localCacheScope=STATEMENT本地会话仅用于语句执行,那么在对同一SqlSession的两个不同调用之间将不会共享数据(禁用缓存,一般不用)。

对于第4条在测试的时候,首先是利用一次会话读取数据,然后将该会话关闭,此时一级缓存中的数据会存到对应的二级缓存中去。之后利用第二个会话首先执行一次clearCache()方法,之后再读取第一个会话之前查找的数据,如果是从缓存中查找的数据,则证明二级缓存没有被清空。代码如下:

	@Test
	public void testSecondLevelCache() throws Exception {
		// 得到sqlSession工厂对象
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		// 开启和数据库的一次会话
		SqlSession session = sqlSessionFactory.openSession();
		SqlSession session2 = sqlSessionFactory.openSession();
		try {
			DepartmentMapper mapper = session.getMapper(DepartmentMapper.class);
			DepartmentMapper mapper2 = session2.getMapper(DepartmentMapper.class);
			
			Department dept01 = mapper.getDeptById(1);
			System.out.println(dept01);
			session.close();
			//测试调用sqlSession.clearCache()方法,看看对二级缓存有没有影响
			session2.clearCache();
			Department dept02 = mapper2.getDeptById(1);
			System.out.println(dept02);
			session2.close();
		} finally {
			
		}
	}

执行结果如下:
在这里插入图片描述
这里可以看到对于同一条查询,在进行了clearCache()方法调用之后,并没有对二级缓存产生什么影响,在第二次调用时是直接从缓存中取的数据。

在这个基础之上,我对里面的内容作出更深一步的探索。假如这里在session这个会话查询完数据之后,执行了clearCache(),会不会对二级缓存产生影响呢。一开始的推断是:session查询完数据,然后去执行clearCache(),会情况session的一级缓存。所以当session进行关闭时,session的一级缓存中没有内容放入DepartmentMapper对应的二级缓存中,自然session2在取数据时需要向数据库发送sql语句进行重新查询。因此,对这一个过程做出了实验,代码修改为如下:

	@Test
	public void testSecondLevelCache() throws Exception {
		// 得到sqlSession工厂对象
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		// 开启和数据库的一次会话
		SqlSession session = sqlSessionFactory.openSession();
		SqlSession session2 = sqlSessionFactory.openSession();
		try {
			DepartmentMapper mapper = session.getMapper(DepartmentMapper.class);
			DepartmentMapper mapper2 = session2.getMapper(DepartmentMapper.class);
			
			Department dept01 = mapper.getDeptById(1);
			System.out.println(dept01);
			//这里在session关闭之前清除了一级缓存,按理说不会有内容进入二级缓存,但是实际效果并不是这样,在mapper2进行查询时仍然从缓存中取得数据
			session.clearCache();
			session.close();
			//测试调用sqlSession.clearCache()方法,看看对二级缓存有没有影响
			//session2.clearCache();
			Department dept02 = mapper2.getDeptById(1);
			System.out.println(dept02);
			session2.close();
		} finally {
			
		}
	}

运行结果如下:
在这里插入图片描述
可以发现,这里在mapper2进行查询时,仍然是从缓存中取得的数据,这就与我们之前所想的“如果在第一个sqlSession对象关闭之前进行清除,那么在该会话关闭时一级缓存中没有东西,自然也就不会把内容放在二级缓存中”这一观点相悖。

Mybatis的缓存机制中二级缓存只有当一级缓存关闭之后,才会将一级缓存中的内容存储在映射文件所对应的二级缓存中去。这里的结果显然不符合这一结论,这里可能是Mybatis的内部设置,包括clearCache()方法执行过程以及Mybatis处理清除缓存的过程有一定得关系。
这里我只对Mybatis自带的Cache接口的一个实现类PerpetualCache进行了研究,发现其clear方法仅仅只是简简单单的对cache存储数据的HashMap进行了一次clear()而已,并没有其他的操作,代码如下:
在这里插入图片描述
可能要深究这一问题的原因还要等挖掘一下Mybatis清除缓存部分的源码。这一问题有待之后解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值