使用Redis做Mybatis的二级缓存
将Redis作为二级缓存
- Mybatis的二级缓存原理不再赘述,大家只要知道,Mybatis的二级缓存可以自动地对数据库的查询做缓存,并且可以在更新数据时同时自动地更新缓存
实现步骤
1.在build.gradle文件中引入redis 依赖
(compile("org.springframework.boot:spring-boot-starter-data-redis:1.5.4.RELEASE"))
2.在application.yml配置文件中进行redis的配置
redis:
# redis数据库索引(默认为0),我们使用索引为3的数据库,避免和其他数据库冲突
database: 0
# redis服务器地址(默认为localhost)
host: 127.0.0.1
# redis端口(默认为6379)
port: 6379
# redis访问密码(默认为空)
password: 123456
# redis连接超时时间(单位为毫秒)
timeout: 0
# redis连接池配置
pool:
# 最大可用连接数(默认为8,负数表示无限)
max-active: 8
# 最大空闲连接数(默认为8,负数表示无限)
max-idle: 8
# 最小空闲连接数(默认为0,该值只有为正数才有作用)
min-idle: 0
# 从连接池中获取连接最大等待时间(默认为-1,单位为毫秒,负数表示无限)
max-wait: -1
3ApplicationContextHolder实现ApplicationContextAware接口,具体内容如下
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
/**
* Get application context from everywhere
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* Get bean by class
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
/**
* Get bean by class name
*
* @param name
* @param <T>
* @return
*/
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
}
4 创建RedisConfig类
@Configuration
@EnableCaching//开启注解
public class RedisConfig {
@Bean
public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
CacheManager cacheManager = new RedisCacheManager(redisTemplate);
return cacheManager;
/*RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
// 多个缓存的名称,目前只定义了一个
rcm.setCacheNames(Arrays.asList("thisredis"));
//设置缓存默认过期时间(秒)
rcm.setDefaultExpiration(600);
return rcm;*/
}
// 以下两种redisTemplate自由根据场景选择
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(serializer);
template.afterPropertiesSet();
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
}
5 创建RedisCache类实现Cache接口,具体内容如下
public class RedisCache implements Cache {
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final String id; // cache instance id
private RedisTemplate redisTemplate;
private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间
public RedisCache(String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
}
@Override
public String getId() {
return id;
}
/**
* Put query result to redis
*
* @param key
* @param value
*/
@Override
@SuppressWarnings("unchecked")
public void putObject(Object key, Object value) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
//此处key 为mapper的id+自动生成的一个key,以mapper的id 为前缀,便于以后删除,这里的id 是mapper 中的namespace
opsForValue.set(id+key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
logger.debug("Put query result to redis");
}
/**
* Get cached query result from redis
*
* @param key
* @return
*/
@Override
public Object getObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
logger.debug("Get cached query result from redis");
return opsForValue.get(id+key);
}
/**
* Remove cached query result from redis
*
* @param key
* @return
*/
@Override
@SuppressWarnings("unchecked")
public Object removeObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.delete(id+key);
logger.debug("Remove cached query result from redis");
return null;
}
/**
* Clears this cache instance
*/
@Override
public void clear() {
RedisTemplate redisTemplate = getRedisTemplate();
//删除所有以mapper的id 开头的key
logger.debug("Clear all the cached query result from redis");
redisTemplate.delete(redisTemplate.keys(id+"*"));
return ;
});
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
private RedisTemplate getRedisTemplate() {
if (redisTemplate == null) {
redisTemplate = ApplicationContextHolder.getBean("redisTemplate");
}
return redisTemplate;
}
}
6实体类中要实现Serializable接口,并且要声明序列号
public class UserBaseInfo implements Serializable{
private static final long serialVersionUID = -2566441764189220519L;
}
7在mapper.xml 中开启缓存
<cache type="org.yungu.demo.springboot.RedisCache"></cache>
运行效果
2018-11-21 10:07:38.758 DEBUG 14290 --- [nio-8080-exec-7] org.yungu.demo.springboot.RedisCache : Get cached query result from redis
2018-11-21 10:07:38.767 DEBUG 14290 --- [nio-8080-exec-7] org.yungu.demo.dao.UserBaseInfoDao : Cache Hit Ratio [org.yungu.demo.dao.UserBaseInfoDao]: 0.5
2018-11-21 10:07:41.884 DEBUG 14290 --- [nio-8080-exec-7] o.y.d.d.U.getUserBaseInfoById : ==> Preparing: SELECT user_base_info.user_id, user_base_info.user_union_id, user_base_info.org_id, user_base_info.`name`, user_base_info.`ename`, user_base_info.`avatar`, user_base_info.nick_name, user_base_info.sex, user_base_info.cert_type, user_base_info.cert_no, user_base_info.mobile, user_base_info.email, user_base_info.tel, user_base_info.name_spelling, user_base_info.nationality_code, user_base_info.deleted, user_base_info.birthday, user_base_info.birth_city_code, user_base_info.birthplace, user_base_info.remarks, user_base_info.create_time, user_base_info.modify_time FROM user_base_info where user_id=? and user_base_info.deleted =0
2018-11-21 10:07:41.886 DEBUG 14290 --- [nio-8080-exec-7] o.y.d.d.U.getUserBaseInfoById : ==> Parameters: 1(Long)
2018-11-21 10:07:41.901 DEBUG 14290 --- [nio-8080-exec-7] o.y.d.d.U.getUserBaseInfoById : <== Total: 1
2018-11-21 10:07:41.904 DEBUG 14290 --- [nio-8080-exec-7] org.yungu.demo.springboot.RedisCache : Put query result to redis
2018-11-21 10:13:32.305 DEBUG 14290 --- [nio-8080-exec-9] org.yungu.demo.springboot.RedisCache : Get cached query result from redis
2018-11-21 10:13:32.322 DEBUG 14290 --- [nio-8080-exec-9] org.yungu.demo.dao.UserBaseInfoDao : Cache Hit Ratio [org.yungu.demo.dao.UserBaseInfoDao]: 0.5555555555555556
2018-11-21 10:15:21.826 DEBUG 14290 --- [nio-8080-exec-1] org.yungu.demo.springboot.RedisCache : Get cached query result from redis
2018-11-21 10:15:21.829 DEBUG 14290 --- [nio-8080-exec-1] org.yungu.demo.dao.UserBaseInfoDao : Cache Hit Ratio [org.yungu.demo.dao.UserBaseInfoDao]: 0.6
2018-11-21 10:15:37.653 DEBUG 14290 --- [nio-8080-exec-4] org.yungu.demo.springboot.RedisCache : Get cached query result from redis
2018-11-21 10:15:37.656 DEBUG 14290 --- [nio-8080-exec-4] org.yungu.demo.dao.UserBaseInfoDao : Cache Hit Ratio [org.yungu.demo.dao.UserBaseInfoDao]: 0.6363636363636364
2018-11-21 10:26:24.492 DEBUG 14290 --- [nio-8080-exec-6] o.y.d.d.UserBaseInfoDao.updateUserInfo : ==> Preparing: update user_base_info set remarks = ? where user_id = ?
2018-11-21 10:26:24.506 DEBUG 14290 --- [nio-8080-exec-6] o.y.d.d.UserBaseInfoDao.updateUserInfo : ==> Parameters: 1111(String), 1(Long)
2018-11-21 10:26:24.525 DEBUG 14290 --- [nio-8080-exec-6] o.y.d.d.UserBaseInfoDao.updateUserInfo : <== Updates: 1
2018-11-21 10:26:26.650 DEBUG 14290 --- [nio-8080-exec-6] org.yungu.demo.springboot.RedisCache : Clear all the cached query result from redis
2018-11-21 10:28:43.540 DEBUG 14290 --- [io-8080-exec-10] org.yungu.demo.springboot.RedisCache : Get cached query result from redis
2018-11-21 10:28:43.549 DEBUG 14290 --- [io-8080-exec-10] org.yungu.demo.dao.UserBaseInfoDao : Cache Hit Ratio [org.yungu.demo.dao.UserBaseInfoDao]: 0.5833333333333334
2018-11-21 10:28:43.555 DEBUG 14290 --- [io-8080-exec-10] o.y.d.d.U.getUserBaseInfoById : ==> Preparing: SELECT user_base_info.user_id, user_base_info.user_union_id, user_base_info.org_id, user_base_info.`name`, user_base_info.`ename`, user_base_info.`avatar`, user_base_info.nick_name, user_base_info.sex, user_base_info.cert_type, user_base_info.cert_no, user_base_info.mobile, user_base_info.email, user_base_info.tel, user_base_info.name_spelling, user_base_info.nationality_code, user_base_info.deleted, user_base_info.birthday, user_base_info.birth_city_code, user_base_info.birthplace, user_base_info.remarks, user_base_info.create_time, user_base_info.modify_time FROM user_base_info where user_id=? and user_base_info.deleted =0
2018-11-21 10:28:43.581 DEBUG 14290 --- [io-8080-exec-10] o.y.d.d.U.getUserBaseInfoById : ==> Parameters: 1(Long)
2018-11-21 10:28:43.595 DEBUG 14290 --- [io-8080-exec-10] o.y.d.d.U.getUserBaseInfoById : <== Total: 1
2018-11-21 10:28:43.617 DEBUG 14290 --- [io-8080-exec-10] org.yungu.demo.springboot.RedisCache : Put query result to redis
2018-11-21 10:31:02.477 DEBUG 14290 --- [nio-8080-exec-3] org.yungu.demo.springboot.RedisCache : Get cached query result from redis
2018-11-21 10:31:02.482 DEBUG 14290 --- [nio-8080-exec-3] org.yungu.demo.dao.UserBaseInfoDao : Cache Hit Ratio [org.yungu.demo.dao