MyBatis的一, 二级缓存
默认MyBatis开启了一级缓存, 在同一个sqlSession中, 如果命中同一个查询, MyBatis是不会真的查询的, 而只是拿结果对象糊弄你一下, 甚至如果这个对象被改了, 它也不管:
@Test public void testCache() { SqlSession sqlSession = getSqlSession(); SysUser user1 = null; try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); user1 = userMapper.selectById(1L); user1.setUserName("New Name"); SysUser resultUser = userMapper.selectById(1L); System.out.println(user1); System.out.println(resultUser); Assert.assertEquals("New Name", resultUser.getUserName()); Assert.assertEquals(user1, resultUser); // 这里的输出很惊人啊, user1改过名字, 理论上resultUser的userName不能跟user1一样啊. // 说明mybatis并未去真的查询, 而直接把结果拿来用了, 甚至对象都是直接拿来用了.可怕. // 这就是缓存的力量? } finally { sqlSession.close(); } System.out.println("开启新的session"); sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); user1 = userMapper.selectById(1L); System.out.println("user1: " + user1); user1.setUserName("New Name"); SysUser resultUser2 = userMapper.selectById(1L); System.out.println(user1); System.out.println(resultUser2); Assert.assertEquals("New Name", resultUser2.getUserName()); Assert.assertEquals(user1, resultUser2); // 这里经过重新开启一个session之后, 又重新搜索了. } finally { sqlSession.close(); } }
这里对象名很乱, 不好意思.
我们发现, 在session没关闭的情况下, 哪怕你把对象用setUserName方法改了, 再查询的时候, 它仍返回一个原来的结果对象, 变成了你查询的结果成了脏数据, 这是MyBatis的一级缓存的威力.
OK, 开启二级缓存.
首先拿SysRole对象做测试, 修改SysRole:
public class SysRole implements Serializable { private static final long serialVersionUID = 3423434546568423L; ... ...
SysRoleMapper的xml文件增加cache, 二级缓存只能针对namespace有效, 故这个namespace下的所有select都进入了缓存范围
<mapper namespace="marc.mybatis.lesson1.mapper.SysRoleMapper"> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="false" />
... ...
Mapper接口加个注解:
@CacheNamespaceRef(SysRoleMapper.class) public interface SysRoleMapper { ... ...
测试类如下, 注意, 这个测试类是拿SysRole而不是SysUser.
@Test public void testLevel2Cache() { SqlSession sqlSession = getSqlSession(); SysRole role1 = null; try { SysRoleMapper roleMapper = sqlSession.getMapper(SysRoleMapper.class); role1 = roleMapper.selectById(1L); role1.setRoleName("New Name"); SysRole roleResult = roleMapper.selectById(1L); System.out.println(role1); System.out.println(roleResult); Assert.assertEquals("New Name", roleResult.getRoleName()); Assert.assertEquals(role1, roleResult); } finally { sqlSession.close(); } System.out.println("开启新的session"); sqlSession = getSqlSession(); try { SysRoleMapper roleMapper = sqlSession.getMapper(SysRoleMapper.class); role1 = roleMapper.selectById(1L); System.out.println("user1: " + role1); //user1.setUserName("New Name"); SysRole resultRole2 = roleMapper.selectById(1L); System.out.println(role1); System.out.println(resultRole2); Assert.assertEquals("New Name", resultRole2.getRoleName()); Assert.assertNotEquals(role1, resultRole2); } finally { sqlSession.close(); } }
输出如下:
DEBUG [main] - Cache Hit Ratio [marc.mybatis.lesson1.mapper.SysRoleMapper]: 0.0 DEBUG [main] - ==> Preparing: select id,role_name roleName,enabled,create_by createBy,create_time createTime from sys_role where id=? DEBUG [main] - ==> Parameters: 1(Long) TRACE [main] - <== Columns: id, roleName, enabled, createBy, createTime TRACE [main] - <== Row: 1, 管理员, 1, 1, 2017-12-09 12:22:12.0 DEBUG [main] - <== Total: 1 DEBUG [main] - Cache Hit Ratio [marc.mybatis.lesson1.mapper.SysRoleMapper]: 0.0 SysRole [id=1, roleName=New Name, enabled=disabled, createBy=1, createTime=Sat Dec 09 12:22:12 CST 2017, user=null, privilegeList=null] SysRole [id=1, roleName=New Name, enabled=disabled, createBy=1, createTime=Sat Dec 09 12:22:12 CST 2017, user=null, privilegeList=null] 开启新的session DEBUG [main] - Cache Hit Ratio [marc.mybatis.lesson1.mapper.SysRoleMapper]: 0.3333333333333333 user1: SysRole [id=1, roleName=New Name, enabled=disabled, createBy=1, createTime=Sat Dec 09 12:22:12 CST 2017, user=null, privilegeList=null] DEBUG [main] - Cache Hit Ratio [marc.mybatis.lesson1.mapper.SysRoleMapper]: 0.5 SysRole [id=1, roleName=New Name, enabled=disabled, createBy=1, createTime=Sat Dec 09 12:22:12 CST 2017, user=null, privilegeList=null] SysRole [id=1, roleName=New Name, enabled=disabled, createBy=1, createTime=Sat Dec 09 12:22:12 CST 2017, user=null, privilegeList=null]
注意, 开启新的session之后, 仍然没有去真的查询, 而是击中了cache, 所以, 命中率一开始1/3, 后来变成了1/2, 而且注意看roleName, 全都被修改过. so, 注意使用缓存时产生的脏数据, 处理好这一点, 会让你的数据库更有效率, 数据吞吐量更大.
想了想, 缓存的好处多半是用于处理搜索把, 比如你十月末在淘宝搜索羽绒服, 如果没有缓存, 数据库会疯掉......