Mybatis的二级缓存是多个SqlSession共享的,作用于是mapper配置文件中同一个namespace,不同的SqlSession两次执行相同namespace下的sql语句且参数如果也一样则最终执行的sql语句是相同的。每次查询都会先看看缓存中是否有对应查询结果,如果有就从缓存拿,如果没有就执行sql语句从数据库中读取,从而提高查询效率。Mybatis默认开启的是一级缓存,所以二级缓存需要自己手动开启。
application.yml
开启二级缓存
mybatis:
mapper-locations: classpath:com/baizhi/mapper/*.xml
executor-type: batch
type-aliases-package: com.baizhi.entities
#开启二级缓存
configuration:
cache-enabled: true
配置redis
#redis配置
redis:
host: 192.168.192.19
port: 6379
timeout: 5s
lettuce:
shutdown-timeout: 100ms
pool:
max-active: 8
max-idle: 8
max-wait: 10ms
min-idle: 1
pom.xml
添加redis依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
添加redisTemplate配置Bean
//redisTemplate
@Bean
public RedisTemplate<Object,Object> redisTemplate(LettuceConnectionFactory connectionFactory) throws UnknownHostException {
RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
//设置key,value序列化
redisTemplate.setKeySerializer(new JdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
实现ApplicationContextAware
该接⼝为标记接⼝,Spring⼯⼚在初始化的时,会⾃动注⼊applicationContext
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
//实现ApplicationContextAware接口的context注入函数, 将其存入静态变量
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//从静态变量ApplicationContext中取得Bean
public static Object getBeanByName(String name){
Object bean = applicationContext.getBean(name);
return bean;
}
}
自定义MyBatisCache实现Cache
//自定义缓存
@Slf4j
public class MyCache implements Cache {
private final String id;
//redis缓存失效时间
private Long timeout = 300L;
private RedisTemplate redisTemplate;
public MyCache(String id){
this.id = id;
}
// 读写锁
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
@Override
public String getId() {
return id;
}
@Override
//加入缓存,第一次查询
public void putObject(Object key, Object value) {
log.info("====加入缓存key:"+key+",value:"+ value +",id:"+id+",第一次查询数据库=======");
redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(key,value,timeout, TimeUnit.MINUTES);
}
@Override
//查询首先查看缓存
public Object getObject(Object key) {
log.info("====查询前首先查看缓存key:"+key+"=id:"+id+"======");
redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
return opsForValue.get(key);
}
@Override
public Object removeObject(Object key) {
log.info("====数据库写操作,删除当前缓存key:"+key+"=======");
redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
Object value = opsForValue.get(key);
redisTemplate.delete(key);
return value;
}
@Override
//一旦修改了数据库删除缓存
public void clear() {
log.info("====清除所有缓存id:"+id+"=======");
redisTemplate = getRedisTemplate();
redisTemplate.execute((RedisConnection connection) ->{
connection.flushAll();
return null;
});
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
public void setTimeout(Long timeout){
this.timeout = timeout;
}
private RedisTemplate getRedisTemplate() {
if (redisTemplate == null) {
redisTemplate = (RedisTemplate) SpringContextHolder.getBeanByName("redisTemplate");
}
return redisTemplate;
}
}
Mapper.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.baizhi.dao.IUserDAO">
<!--开启二级缓存-->
<cache type="com.baizhi.cache.MyCache">
<property name="timeout" value="1000"/>
</cache>
对于有不需要用到二级缓存的语句可以在标签内写userCache=“false”,默认为true开启缓存。
<!--模糊分页查询-->
<select id="queryUserByPage" resultType="User" useCache="false" flushCache="false">
select <include refid="selectAll"/> from t_user
<where>
<if test="column != null and column != '' and value != ''">
${column} like "%"#{value}"%"
</if>
</where>
limit #{pageNow},#{pageSize}
</select>
(select 默认useCache为true:使用缓存,flushCache为false:不清空缓存)
(insert、update、delete 默认flushCache为true:清空缓存)