概述
使用MyBatis
自身的设置开启二级缓存,在分布式系统下将不起作用,因此,我们才用中间件开启二级缓存,此文介绍了使用Redis
开启二级的解决策略。本文介绍了2种使用redis的开启二级缓存的机制,使用Jedis 和 lettuce。
第一种策略 使用:Jedis
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
①引入依赖
<!--redis的启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
②配置redis参数
在application.yml
文件中添加:
#设置redis的参数
spring:
# redis: #单机模式
# host: 192.168.*.*
# port: 6379
redis: #集群模式
cluster:
nodes: 192.168.8.18:7004,192.168.8:7001,192.168.8:7002
③获取SprnigBoot工厂后门
定义一个web触发器,作用是获得整个工厂内容,方便非工厂管理的普通类,可以拿到工厂管理的对象(全局容器)
我们这么做,是为了获取 被工厂管理的redisTemplate
对象。
package com.baizhi.cache;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
//web触发器,作用是获得整个工厂内容,方便非工厂管理的普通类。可以拿到工厂管理的对象(全局容器)
@Component
public class WebWare implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//通过属性名获取对象的方法
public static Object getbyName(String name){
Object bean = applicationContext.getBean(name);
return bean;
}
//通过属性类获取对象的方法
public static Object getByClass(Class clazz){
Object bean = applicationContext.getBean(clazz);
return bean;
}
}
④自定义缓存机制
Mybatis
的cache,给需要集成其它Cache或者自定义Cache提供了接口。
package com.baizhi.cache;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.locks.ReadWriteLock;
//定义自己的一个缓存策略
public class MyCache implements Cache {
//获取工厂管理的redisTemplate对象
private RedisTemplate redisTemplate = (RedisTemplate) WebWare.getbyName("redisTemplate");
private String id;
public MyCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object o, Object o1) {
redisTemplate.opsForHash().put(id,o,o1);
}
@Override
public Object getObject(Object o) {
Object o1 = redisTemplate.opsForHash().get(id, o);
return o1;
}
@Override
public Object removeObject(Object o) {
return null;
}
//清空缓存
@Override
public void clear() {
redisTemplate.delete(id);
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}
⑤启用二级缓存
在*mapper.xml
文件中添加以下内容:
<cache type="com.baizhi.cache.MyCache"></cache>
第二种策略 使用 Lettuce
Lettuce的连接是基于Netty的,连接实例可以在多个线程间并发访问,并且是线程安全的,所以一个连接实例就可以满足多线程环境下的并发访问
①引入依赖
<!--集成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>
②配置redis参数
#连接redis
redis:
host: hbase
port: 6379
timeout: 5s #超时时间
lettuce:
pool:
max-active: 10 #最大活动数
max-idle: 8 #最大闲置数
max-wait: 5ms #最大等待数
min-idle: 1 #最小闲置数
shutdown-timeout: 100ms #超时停机时间
③在入口类中注册组件
package com.baizhi;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.web.client.RestTemplate;
import java.net.UnknownHostException;
@SpringBootApplication
@MapperScan("com.baizhi.dao")
public class UsermodelApplication {
public static void main(String[] args) {
SpringApplication.run(UsermodelApplication.class, args);
}
//注册一个Rest组件 SpringMVC中自带的一个Rest客户端工具,可以无缝和SpringBoot集成
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
//注册一个Redis池技术的组件 Lettuce
@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;
}
}
④获取工厂后门
package com.baizhi.cache;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class WebWare implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//通过属性名获取对象的方法
public static Object getbyName(String name){
Object bean = applicationContext.getBean(name);
return bean;
}
//通过属性类获取对象的方法
public static Object getByClass(Class clazz){
Object bean = applicationContext.getBean(clazz);
return bean;
}
}
⑤自定义缓存机制
package com.baizhi.cache;
import org.apache.ibatis.cache.Cache;
import org.aspectj.weaver.ast.Var;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyCache implements Cache {
private Logger logger= LoggerFactory.getLogger(MyCache.class);
//获取RedisTemple 对象
//获取工厂管理的redisTemplate对象
private RedisTemplate redisTemplate = (RedisTemplate) WebWare.getbyName("redisTemplate");
//创建一个读写锁
private ReadWriteLock lock = new ReentrantReadWriteLock();
//设置一个超时配置
private long timeout=300;
//id 用于存放namespace
private String id;
//提供一个构造
public MyCache(String id) {
this.id = id;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
@Override
public String getId() {
return id;
}
@Override // o 某一方法的唯一标识 o1 方法的返回值
public void putObject(Object o, Object o1) {
/* redisTemplate.opsForHash().put(id,o,o1);*/
logger.debug("将查询结果存储到cache.key:"+o+",value:"+o1);
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(o,o1,timeout, TimeUnit.SECONDS);
}
@Override
public Object getObject(Object o) {
/*return redisTemplate.opsForHash().get(id,o);*/
logger.debug("从缓存中读取结果.key:"+o);
ValueOperations opsForValue = redisTemplate.opsForValue();
return opsForValue.get(o);
}
@Override
public Object removeObject(Object o) {
logger.debug("从缓存中清除.key:"+o);
ValueOperations opsForValue = redisTemplate.opsForValue();
Object value = opsForValue.get(o);
redisTemplate.delete(o);
return value;
}
@Override
public void clear() {
//清除
/* redisTemplate.delete(id);*/
logger.debug("从缓存中清除缓存区所有数据");
redisTemplate.execute((RedisConnection connection) ->{
connection.flushAll();
return null;
});
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return lock;
}
}
⑥启用二级缓存
<!--开启二级缓存-->
<cache type="com.baizhi.cache.MyCache">
<!--设置超时时间-->
<property name="timeout" value="60"/>
</cache>