强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan
使用缓存可以提高获取数据的速度,避免频繁的数据库交互,尤其是在查询越多,缓存命中率越高的情况下,使用缓存的作用就更加明显了。一般提到Mybatis缓存的时候都是指二级缓存,一级缓存默认会启用。
1.先写一个基本的mapper来创建sqlsession,类名为BaseMapperTest
public class BaseMapperTest
{
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init(){
try{
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
}catch (IOException ignore){
ignore.printStackTrace();
}
}
public SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2.创建一个缓存的测试类,CacheTest
public class CacheTest extends BaseMapperTest {
@Test
public void testL1Cache(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
SysUser user1 = null;
try {
//获取UserMapper接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用selectById方法
user1 = userMapper.selectById(1L);
//对当前获取的对象重新赋值
user1.setUserName("New Name");
//再次查询获取id相同的用户
SysUser user2 = userMapper.selectById(1L);
//虽然没有更新数据库,但是user1和user2的名字相同
Assert.assertEquals("New Name",user2.getUserName());
//无论如何user1和user2是同一个实例
Assert.assertEquals(user1,user2);
}finally {
sqlSession.close();
}
System.out.println("开启新的SqlSession");
//开启一个新的sqlsession
sqlSession = getSqlSession();
try {
//获取UserMapper接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user2 = userMapper.selectById(1L);
Assert.assertNotEquals("New Name",user2.getUserName());
//这里的user2和前一个session查询的结果是两个不同的实例
Assert.assertNotEquals(user1,user2);
//执行删除操作
userMapper.deleteById(2L);
//获取user3
SysUser user3 = userMapper.selectById(1L);
//这里的user2和user3是两个不同的实例
Assert.assertNotEquals(user2,user3);
}finally {
sqlSession.close();
}
}
}
运行结果如下,在第一个try语句块中,我们写了两次查询数据库的语句,但是打印出的sql只有一条,证明第二条没有查询数据库,而是查询了缓存,并且user1和user2是同一个实例,先从数据库中获取user1的值,user1重新对userName赋值,第二次查询user2发现user2的userName是user1修改后的值。
Mybatis一级缓存存在于SqlSession的生命周期中,在同一个SqlSession中查询时,Mybatis会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果放到一个Map中,如果同一个SqlSession中执行的方法和参数完全一致,那么通过算法生成相同的键值,当Map缓存对象中已经 存在该键值时,则会返回缓存中的对象.
如果不想使用缓存怎么办呢?可以在Mapper的方法上添加一个flushCache="true"的配置,他会在执行查询之前将缓存清除。
第二个try语句块中我们重新获取了一个新的sqlsession,查询结果显示,user2和第一个语句块中的user1没有任何关系,当我们执行删除操作后,用同一个sqlsession执行相同的查询,结果赋值给user3,结果表示user2和user3是不同的实例,原因是因为所有的insert,update,delete操作都会清空一级缓存。
Mybatis的二级缓存不同于一级缓存,一级缓存存在于sqlsession的生命周期中,而二级缓存可以理解为存在sqlsessionFactory的生命周期中。
1.Mybatis配置文件的简单配置
在Mybatis的全局配置settings中有一个参数cacheEnabled,这个参数是二级缓存的全局开关.默认为true,所以可以不配置,如果将其设置为false,则在后边所有缓存的配置都不起作用了。
在mapper中加一个cache标签即可。
默认的二级缓存的效果:
所有的Select语句将会被缓存
映射语句中所有的insert,update,delete操作会刷新缓存
缓存会使用LRU算法来回收
缓存会存储集合或对象的1024个引用
缓存会被视为read/write的
3.Mapper接口中配置二级缓存
在接口上加上@CacheNamespace属性,如果在接口和XML同时配置了缓存,则需要用到参照缓存,否则会报错,写法是在接口上写@CacheNamespaceRef(XXXMapper.Class)
Mybatis默认提供的缓存是基于map实现的内存缓存,可以满足基本使用,当数据量大的时候可以借助一些缓存框架或Redis缓存来协助保存Mybatis的二级缓存数据。