一、配置二级缓存
1. 在mybatis_config.xml中进行如下配置:
<setting name="cacheEnabled" value="true"/>
其实这里的二级缓存默认是出于开启状态,因此这个位置可以不进行配置,知道有这么回事儿即可。
2.MyBatis二级缓存是和命名空间是绑定的 ,即二级缓存需要配置在 Mapper.xml 映射文件中,或者配置在 Mapper.java 接口中。在映射文件中命名空间就是 XML 根节点 mapper namespace 属性 Mapper 接口中,命名空间就是接口的全限定名称。
(1)在RoleMapper.xml中进行二级缓存配置,添加配置如下:
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.example.simple.mapper.RoleMapper"> <cache eviction="FIFO" flushInterval="6000" size="512" readOnly="false"/> /mapper>
(2)在RoleMapper.java类中添加注解:
@CacheNamespaceRef(RoleMapper.class) public interface RoleMapper { //代码 }
最基本的二级缓存就配置好了。
二、使用二级缓存
上面的配置是可读写的缓存,而 MyBatis使用 SerializedCache序列化缓存来实现可读写缓存类,井通过序列化和反序列化来保证通过缓存获取数据时,得到的是一个新的实例。因此,如果配置为只读缓存,Mybatis就会使用 Map 来存储缓存值,这种情况下 ,从缓存中获取的对象就是同一个实例。
1. 因为使用可读写缓存,可以使用 SerializedCache 序列 缓存。这个缓存类要求所有被序列化的对象必须实现 Serializable (java.io.Serializable )接口,所以还需要修改 SysRole 对象 ,代码如下:public class SysRole implements Serializable { private static final long serialVersionUID = 6320941908222932112L ; /* * 其他方法 * */ }
2. 编写测试方法如下:
@Test public void testCache2(){ SqlSession sqlSession = getSqlSession(); SysRole role = null; try{ RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); role = roleMapper.selectById(1l); role.setRoleName("new name"); SysRole role1 = roleMapper.selectById(1l); Assert.assertEquals(role1.getRoleName() , "new name"); Assert.assertEquals(role,role1); }finally { sqlSession.close(); } System.out.println("开启新一个sqlSession" ); sqlSession = getSqlSession(); try{ RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); SysRole role1 = roleMapper.selectById(1l); Assert.assertEquals(role1.getRoleName(),"new name"); Assert.assertNotEquals(role,role1); SysRole role2 = roleMapper.selectById(1l); Assert.assertNotEquals(role1,role2); }finally { } }
测试结果如下:
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.0
DEBUG [main] - ==> Preparing: select id, role_name,enabled,create_by,create_time from sys_role where id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, role_name, enabled, create_by, create_time
TRACE [main] - <== Row: 1, 管理员, 1, 1, 2020-12-01 20:05:01
DEBUG [main] - <== Total: 1
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.0
开启新一个sqlSession
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.3333333333333333
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.5
解析:
日志中存在好几条以 Cache Hit Ratio 开头的语句 ,这行日志后面输出的值为当前执行方法的缓存命中率,在测试第一部分中,第一次查询获取 rolel 的时候由于没有缓存,所以执
行了数据库查询。在第二个查询获取 role2 的时候, role2和rolel 是完全相同的实例,这里使用的是一级缓存,所以返回同一个实例。 调用 close 方法关闭 SqlSession 时, SqlSession 才会保存查询数据到二级缓存中,在这之后二级缓存才有了缓存数据,所以可以看到在第一部分的两次查询时,命中率都是0;在第二部分测试代码中,再次获取 role2 时,日志中并没有输出数据库查询,而是输出了命中率,这时的命中率是 0.3333333333333333 ,这是第三次查询,并且得到了缓存的值,因此该方法 共被请求了3次,有一次命中,所以命中率就是三分之一。 后面再获取 role3 的时候,就是四次请求,两次命中,命中率为 0.5 。并且因为可读写缓存的缘故, role2和role3 都是反序列化得到的结果 ,所以它们不是相同的实例,在这 部分,这两个实例是读写安全的,其属性不会互相影响。 至此,告一段落。