Mybatis缓存配置—— 一级缓存
一级缓存又叫做本地缓存,在程序启动的时候就会正常启动,一般不加以设置的话就是默认启动一级缓存模式,先看一下一级缓存到底是如何起到作用的。
1. 正在com.example.simple下新建CacheTest类,代码如下:
package com.example.simple.mapper; import com.example.simple.model.SysUser; import org.apache.ibatis.session.SqlSession; import org.junit.Assert; import org.junit.Test; public class CacheTest extends BaseMapperTest { @Test public void testL1Cache(){ SqlSession sqlSession = getSqlSession(); SysUser user = null; try{ UserMapper userMapper = sqlSession.getMapper(UserMapper.class); user = userMapper.selectById(1l); System.out.println("第二次查询————"); user.setUserName("new name"); SysUser user1 = userMapper.selectById(1l); Assert.assertEquals(user1.getUserName(),"new name"); Assert.assertEquals(user,user1); }finally { sqlSession.close(); } System.out.println("开启新的sqlSession"); sqlSession = getSqlSession(); try{ UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser user1 = userMapper.selectById(1l); Assert.assertNotEquals("new name" , user1.getUserName()); Assert.assertNotEquals(user1,user); userMapper.deleteById(2l); SysUser user2 = userMapper.selectById(1l); Assert.assertNotEquals(user1,user2); }finally { sqlSession.close(); } } }
测试结果如下:
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
第二次查询————
开启新的sqlSession
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
DEBUG [main] - ==> Preparing: delete from mybatis.sys_user u where u.id = ?
DEBUG [main] - ==> Parameters: 2(Long)
DEBUG [main] - <== Updates: 0
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
解析:从测试结果可以看出,
开启的第一个sqlSession中,数据库查询执行完第一个selectById后就没再执行下一个selectById了,而且Assert.assertEquals(user,user1);也并没有出现异常,说明user和user1此时判断出二者是同一实例,即使user和user1两者的username并不一样,这就是mybatis一级缓存在捣鬼了。MyBatis一级缓存存在于 SqlSession 的生命周期中,在同一SqlSession 中查询时, MyBatis 会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果存入一个 Map对象中。如果同一个 SqlSession 中执行的方法和参数完全一致,那么通过算法会生成相同键值,当 Map 缓存对象中己经存在该键值时,则会返回缓存中的对象。这样一来,就出现了两次selectById函数执行却执行了一次的情况的原因就能得到合理的解释。
开启的第二个sqlSession中,两次selectById函数都得到了执行,而且user1和user2这次执行出来并不是同一实例,这又是为什么呢?这段代码和上一段代码的差异在于这段代码在中间执行了一个 deleteById 操作 ,然后使用相同的方法和参数获取了 user2 实例,从日志和结果来看, user2和user1 也是完全不同的两个对象。这是因为任何的 INSERT、UPDATE、DELETE 操作都会清空一级缓存,所以查询 user2 的时候由于缓存不存在,就会再一次执行数据库查询获取数据。这时二者自然就不会是同一个实例了。
改进:在使用 MyBatis的过程中,要避免在使用如上代码中的 user1 时出现的错误。我们可能以为获取的 user1 应该是数据库中的数据,却不知道 user的一个重新赋值会影响到 user2,如果不想让 selectByid 方法使用一级缓存 ,可以对该方法做如下修改。
<select id="selectById" flushCache="true" resultMap="userMap"> select * from sys_user where id = #{id} </select>
这时执行情况如下:(注释掉如下代码执行)
//Assert.assertEquals(user1.getUserName(),"new name"); //Assert.assertEquals(user,user1);
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
第二次查询————
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
开启新的sqlSession
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
DEBUG [main] - ==> Preparing: delete from mybatis.sys_user u where u.id = ?
DEBUG [main] - ==> Parameters: 2(Long)
DEBUG [main] - <== Updates: 0
DEBUG [main] - ==> Preparing: select * from sys_user where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@com.example, <<BLOB>>, <<BLOB>>, 2020-12-01 20:02:01
DEBUG [main] - <== Total: 1
一级缓存成功被清空。