05-Mybatis一级缓存,二级缓存详解
一,mybatis一级缓存
mybatis提供查询缓存,如果缓存中又数据,就不用从数据库中获取,用于减轻数据压力,提高系统性能。
我们用一张图来表示一级缓存和二级缓存的位置:
1.一级缓存是sqlSession级别的缓存。
2.二级缓存是Mapper级别的缓存。
一级缓存是sqlSession级别的缓存,在操作数据库的时候,需要构造sqlSession对象,在对象中又一个数据结构(HashMap)用于存储缓存数据,不同的sqlSession的缓存区域(HashMap)是互相不受影响的。
mybatis默认是支持一级缓存的。
一,证明一级缓存的存在:
验证方法:
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取UserMapper的代理类
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//第一次查询
User user = userMapper.findUserById(10);
System.out.println(user);
//第二次查询
User user2 = userMapper.findUserById(10);
System.out.println(user2);
sqlSes
通过执行该方法,查看打印日志可以看出就执行了一次sql语句的查询,因此可以判断第二次查询是没有从数据库中进行查询的。
思考:那么什么时候一级缓存会清空呢?
通过测试发现,当在第二次查询数据库之前对数据库进行了写的操作后,第二次查询就不会从缓存中查询结果了,而是直接从数据库中查询结果。另外一种就是在第一次查询结果后,手动的方式清空一级缓存(使用sqlSession.clearCache()方法)
测试方法:
二,mybatis二级缓存
二级缓存是Mapper级别的缓存。多个SqlSession去操作同一个Mapper得sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession。(二级缓存Mybatis默认是关闭得,需要自己去手动配置开启或可以自己选择使用哪个厂家得缓存来作为二级缓存)
一,开启二级缓存
首先在全局配置文件中配置开启二级缓存功能;
<!-- 开启二级缓存总开关 -->
<setting name="cacheEnabled" value="true"/>
在映射文件中去选择是否该映射文件使用二级缓存:
如果使用就进行一下配置,如果不用,就不需要对映射文件做任何修改。
<!-- 开启本mapper下的namespace的二级缓存,默认使用的是mybatis提供的PerpetualCache -->
<cache></cache>
也可以设置选择二级缓存
选择使用EhcacheCache缓存(注意:在使用EhcacheCache缓存需要导入jar包)
<!-- 拓展第三方二级缓存,使用type属性,并写第三方缓存得全限定名 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache" />
最后就是,在需要缓存得po类中去实现序列化:
package com.qinzi.accountsystem.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.persistence.Column;
import java.io.Serializable;
import java.util.Date;
@Slf4j
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
@Column(name="id")
private Long id;
@Column(name="name")
private String userName;
@Column(name="pwd")
private String passWord;
@Column(name="age")
private Integer age;
@Column(name="sex")
private Integer sex;
@Column(name="birth")
private Date birth;
@Column(name="phone")
private String phone;
@Column(name="email")
private String email;
}
验证二级缓存是否开启:
@Test
//测试二级缓存是否开启
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
//获取UserMapper的代理类
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(10);
System.out.println(user1);
//当sqlSession1执行close()的时候,才把sqlSession1查询的结果写到二级缓存中去。
sqlSession1.close();
// User u = new User();
// u.setUsername("小胖");
// u.setAddress("成都");
// u.setSex("2");
// u.setBirthday(new Date());
// userMapper3.insertUser(u);
// //当其中任何一个sqlSession执行commit()方法后将刷新整个缓存区
// sqlSession3.commit();
// sqlSession3.close();
//第二次查询
User user2 = userMapper2.findUserById(10);
System.out.println(user2);
sqlSession2.close();
}
测试结果:
二,禁用二级缓存
由于二级缓存默认是关闭的,如果不开启就不会使用二级缓存。如果,我们开启了二级缓存,而在有些查询结果集中,不需要收到二级缓存影响,该怎么去做呢?
在select查询中,默认是使用了二级缓存,如果不想使用二级缓存,就在select标签中又一个userCache的属性设置为false,就代表不使用二级缓存,每次进行查询数据都不会从缓存中获取,而是直接从数据库中进行查询。useCache的默认值是true,即代表statement使用二级缓存。
三,刷新二级缓存
在statement中设置flushCache=true,可以刷新二级缓存。默认情况下,select语句中的flushCache是false。如果是insert,update,delete语句,那么flushCache的默认值是true。如果将select语句中的flushCache值改为true,就意味这查询语句的二级缓存失效,每次查询都会从数据库中进行查询。如果将select语句的flushCache值为false,就代表该查询语句使用了二级缓存,如果在数据库中修改了数据,而二级缓存中的数据还是原来的数据,那么这样就会出现脏读。
flushCache设置如下: