一、mybatis缓存介绍
在mybatis框架中存在有缓存数据功能。
mybatis中缓存区域分为一级缓存和二级缓存,如下图:
mybatis中,一级缓存的作用域在一个sqlsession中,在同一个sqlsession中执行两个相同的sql语句,第一次执行的sql语句后的结果数据将会写入到缓存中,第二次执行时就不会再去数据库中查询,直接会去缓存中获取,从而提高查询效率。当一个sqlsession结束后该sqlsession中的一级缓存就不存在了。mybatis默认开启一级缓存。
mybatis的二级缓存是多个sqlsession共享的,它的作用于是mapper的同一个namespace,不同的sqlsession执行相同namespace下的sql语句且向sql语句中传递的参数也相同。即最终执行相同的sql语句,第一次会将执行的结果写入二级缓存中,第二次执行相同的sql时不会再去数据库查询,直接从缓存中取数据,从而提升了查询效率。mybatis默认没有开启二级缓存,需要在setting全局参数中配置开启二级缓存。
在主配置文件中添加以下配置
<settings>
<setting name="cacheEnabled" value="true" />
</settings>
在需要开启二级缓存的mapper映射文件中添加以下代码(在 < mapper namespace>下方)
<cache />
二、一级缓存
1、原理
上图是查询id为1的用户图解,这整个就是一个sqlsession,一级缓存是根据sqlsession为单位来划分的。
每次查询都会先从缓存中查找,若没有才会到数据库中查找,查询到的数据再写入缓存中。
mybatis内部存储缓存使用一个hashmap,key为hashcode+sqlID+sql语句组成,value为从查询中映射出的java对象
sqlsession执行insert、update、delete登操作commit提交后会清空缓存区全部内容。
2、测试
//获取session
SqlSession session = sessionFactory.openSession();
//获限mapper接口实例
SysUserDao userMapper = session.getMapper(SysUserDao.class);
//第一次查询
SysUser user1 = userMapper.findUserById(1);
System.out.println(user1);
// 第二次查询,由于是同一个session则不再向数据发出语句直接从缓存取出
SysUser user2 = userMapper.findUserById(1);
System.out.println(user2);
// 关闭session
session.close();
执行后的结果地址相同,说明第一次的结果和第二次的结果在内存中是同一个。
edu.mybatis2.pojo.SysUser@6b9651f3
edu.mybatis2.pojo.SysUser@6b9651f3
执行第一次查询后执行添加操作,再执行第二次查询
//获取session
SqlSession session = sessionFactory.openSession();
//获限mapper接口实例
SysUserDao userMapper = session.getMapper(SysUserDao.class);
//第一次查询
SysUser user1 = userMapper.findUserById(1);
System.out.println(user1);
//添加一条数据
SysUser user = new SysUser();
user.setUid(UUID.randomUUID().toString());
user.setUsername("张三");
user.setUserpwd("6666");
userMapper.insert(user);
// 第二次查询,由于是同一个session则不再向数据发出语句直接从缓存取出
SysUser user2 = userMapper.findUserById(1);
System.out.println(user2);
// 关闭session
session.close();
最后结果在内存中的地址不相同,说明两次查询的结果不是同一个。
edu.mybatis2.pojo.SysUser@6b9651f3
edu.mybatis2.pojo.SysUser@262b2c86
三、二级缓存
1、原理
二级缓存区域是根据mapper的namespace划分的,相同的namespace的mapper查询的数据放在同一个区域,如果使用mapper代理方法每个mapper的namespace都不同,此时可以理解为二级缓存区域是根据mapper。
每次查询都会先从缓存查找,如果找不到从数据库查询,查询到数据将数据写入缓存。Mybatis 内部存储缓存使用一个 HashMap,key 为hashCode+sqlId+Sql 语句。value 为 从查询出来的结果数据 。sqlSession 执行 insert、update、delete 等操作 commit 提交后会清空缓存区域。
2、开启二级缓存
在核心配置文件中加入
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
要在你的 Mapper 映射文件中添加一行: < cache /> ,表示此 mapper 开启二级缓存。
3、测试
//获取session
SqlSession session1 = sessionFactory.openSession();
//获限mapper接口实例
SysUserDao userMapper1 = session1.getMapper(SysUserDao.class);
//第一次查询
SysUser user1 = userMapper1.findUserById(1);
System.out.println(user1);
session1.close();
SqlSession session2 = sessionFactory.openSession();
SysUserDao userMapper2 = session2.getMapper(SysUserDao.class);
// 第二次查询,由于是同一个session则不再向数据发出语句直接从缓存取出
SysUser user2 = userMapper2.findUserById(1);
System.out.println(user2);
// 关闭session
session2.close();
ps:验证方式,debug模式下人为修改数据库可验证。
4、实现序列化
二级缓存需要查询结果映射的 pojo 对象实现 java.io.Serializable 接口实现序列化和反序 列化操作,注意如果存在父类、成员 pojo 都需要实现序列化接口。
public class SysUser implements Serializable
5、禁用二级缓存
在 statement 中设置 useCache=false 可以禁用当前 select 语句的二级缓存,即每次查询都会 发出 sql 去查询,默认情况是 true,即该 sql 使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
6、刷新缓存
在 mapper 的同一个 namespace 中,如果有其它 insert、update、delete 操作数据后需要刷新 缓存,如果不执行刷新缓存会出现脏读。
设置 statement 配置中的 flushCache=“true” 属性,默认情况下为 true 即刷新缓存,如果改成 false 则不会刷新。
使用缓存时如果手动修改数据库表中的查询数据会出现脏读。 如下:
<insert id="insertUser" parameterType="edu.etime.mybatis.pojo.User" flushCache="true">