缓存流程图
缓存实战
准备工作
复制项目,修改名称
引入jar包
<!--springboot整合redis jar 开始-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--springboot整合redis jar 结束-->
编写Cache接口的实现类
package com.aaa.sbm.util;
import io.swagger.models.auth.In;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @FileName: MyCustomCache
* @Description:
* @Author: zhz
* @CreateTime: 2024/12/4 11:53
* @Version: 1.0.0
*/
//@Component
public class MyCustomCache implements Cache {
//缓存对象的唯一id
private String id;
//ReentrantReadWriteLock 可重入的读写锁 redis缓存的对象的读写策略 读读共享 读写互斥 写读互斥 写写互斥
private static ReadWriteLock readWriteLock =new ReentrantReadWriteLock();
//jedis连接redis的工厂类 创建一个一个的连接
//@Resource
private static JedisConnectionFactory jedisConnectionFactory;
/**
* 配置一个静态注入方法
* @param jedisConnectionFactory
*/
public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
MyCustomCache.jedisConnectionFactory = jedisConnectionFactory;
}
public MyCustomCache() {
}
/**
* //type 属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口,
* // 且提供一个接受 String 参数作为 id 的构造器。
* @param id
*/
public MyCustomCache(String id) {
//判断是否为null
if(StringUtils.isEmpty(id)){
//如果null就抛出异常
throw new IllegalArgumentException("id不能为null!");
}
this.id = id;
}
/**
* 返回当前缓存对象的唯一识别
* @return
*/
@Override
public String getId() {
return this.id;
}
/**
* 添加缓存
* @param key
* @param value
*/
@Override
public void putObject(Object key, Object value) {
//使用工厂创建redis链接对象
RedisConnection connection = jedisConnectionFactory.getConnection();
//序列化key和value
//1,实例化序列化和反序列对象
JdkSerializationRedisSerializer jdkSerializationRedisSerializer =new JdkSerializationRedisSerializer();
//2,序列化KV
byte[] serializeKey = jdkSerializationRedisSerializer.serialize(key);
byte[] serializeValue = jdkSerializationRedisSerializer.serialize(value);
//要求存入的序列化过的key和value
connection.set(serializeKey,serializeValue);
//不要执行关闭,因为我要提高效率,使用redis连接池技术 ,连接池会自己管理链接,所以不用自行关闭
//connection.close();
}
/**
* 根据key获取缓存
* @param key
* @return
*/
@Override
public Object getObject(Object key) {
//使用工厂创建redis链接对象
RedisConnection connection = jedisConnectionFactory.getConnection();
//序列化key和value
//1,实例化序列化和反序列对象
JdkSerializationRedisSerializer jdkSerializationRedisSerializer =new JdkSerializationRedisSerializer();
//2,序列化K
byte[] serializeKey = jdkSerializationRedisSerializer.serialize(key);
//3,根据序列化的key获取到序列化的值
byte[] serializeValue = connection.get(serializeKey);
//4,反序列化,把字节数组变回对象 并返回
return jdkSerializationRedisSerializer.deserialize(serializeValue);
}
/**
* 根据key删除缓存
* @param key
* @return
*/
@Override
public Object removeObject(Object key) {
//使用工厂创建redis链接对象
RedisConnection connection = jedisConnectionFactory.getConnection();
//序列化key和value
//1,实例化序列化和反序列对象
JdkSerializationRedisSerializer jdkSerializationRedisSerializer =new JdkSerializationRedisSerializer();
//2,序列化K
byte[] serializeKey = jdkSerializationRedisSerializer.serialize(key);
//直接删除,但是不好,可能会影响redis效率
//return connection.del(serializeKey);
//设置立马过期,并不是真正的删除,redis底层会调用过期key的删除策略 批量删除,提高redis效率
return connection.expire(serializeKey,0);
}
/**
* 清空所有缓存
*/
@Override
public void clear() {
//使用工厂创建redis链接对象
RedisConnection connection = jedisConnectionFactory.getConnection();
//清空当前库
connection.flushDb();
//清空所有库 使用主从或者哨兵,有16库时使用
connection.flushAll();
}
/**
* 获取缓存的数量
* @return
*/
@Override
public int getSize() {
//使用工厂创建redis链接对象
RedisConnection connection = jedisConnectionFactory.getConnection();
//获取当前库的key的数量
Long aLong = connection.dbSize();
//转换并返回
return Integer.valueOf(aLong.toString());
}
/**
* 对缓存的读写策略
* @return
*/
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
}
缓存理论
https://mybatis.p2hp.com/sqlmap-xml.html#cache
Cache配置及第三方接口的讲解
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
配置spring整合redis
package com.aaa.sbm.config;
import com.aaa.sbm.property.RedisProperty;
import com.aaa.sbm.util.MyCustomCache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
import javax.annotation.Resource;
/**
* @FileName: SpringRedisConfig
* @Description: spring整合redis的配置
* @Author: zhz
* @CreateTime: 2024/12/5 9:44
* @Version: 1.0.0
*/
@Configuration //相当于spring-redis-config.xml <beans>
public class SpringRedisConfig {
//常量 硬编码 魔法值
// private final static String CLUSTER_NODE_STR = "192.168.170.21:8001,192.168.170.21:8002,192.168.170.22:8003,192.168.170.22:8004,192.168.170.23:8005,192.168.170.23:8006";
// private final static Boolean TEST_ON_BORROW=false;
@Resource
private RedisProperty redisProperty;
/**
* 实例化jedisConnectionFactory
* @return
*/
@Bean //<bean id='jedisConnectionFactory' class=org.springframework.data.redis.connection.jedis.JedisConnectionFactory>
public JedisConnectionFactory jedisConnectionFactory(){
//实例化 RedisClusterConfiguration clusterConfig, JedisPoolConfig poolConfig
JedisConnectionFactory jedisConnectionFactory =new JedisConnectionFactory(clusterConfig(),poolConfig());
return jedisConnectionFactory;
}
/**
* 把当前类配置好的jedisConnectionFactory对象注入到MyCustomCache中使用
*/
@Bean
public void setJCF(){
MyCustomCache.setJedisConnectionFactory(jedisConnectionFactory());
}
/**
* 实例化 redis的集群配置
* @return
*/
@Bean
public RedisClusterConfiguration clusterConfig(){
//实例化
RedisClusterConfiguration redisClusterConfiguration =new RedisClusterConfiguration();
//"192.168.170.21:8001,192.168.170.21:8002,192.168.170.22:8003,192.168.170.22:8004,192.168.170.23:8005,192.168.170.23:8006";
//hostAndPortArray=["192.168.170.21:8001","192.168.170.21:8002"...]
String[] hostAndPortArray = redisProperty.getNodes().split(",");
//循环
for (String hostAndPort : hostAndPortArray) {
//hostAndPort 第1次192.168.170.21:8001
//hostAndPort 第1次192.168.170.21:8002
//...
String[] hostPort = hostAndPort.split(":");
//实例化redis节点对象
RedisNode node = new RedisNode(hostPort[0],Integer.valueOf(hostPort[1]));
//添加集群节点
redisClusterConfiguration.addClusterNode(node);
}
return redisClusterConfiguration;
}
/**
* 实例化 redis的连接池配置
* @return
*/
@Bean
public JedisPoolConfig poolConfig(){
//实例化
JedisPoolConfig jedisPoolConfig =new JedisPoolConfig();
//魔法值
//连接池设置
//使用连接时是否检查
jedisPoolConfig.setTestOnBorrow(redisProperty.getTestOnBorrow());
//归还链接时是否要检查
jedisPoolConfig.setTestOnReturn(redisProperty.getTestOnReturn());
//设置最大连接数
jedisPoolConfig.setMaxTotal(redisProperty.getMaxTotal());
//设置最大空闲时长
jedisPoolConfig.setMaxIdle(redisProperty.getMaxIdle());
//设置最大等待时长
jedisPoolConfig.setMaxWaitMillis(redisProperty.getMaxWaitMillis());
//....
return jedisPoolConfig;
}
}
Mapper配置缓存
<!--二级缓存 缓存到第三方redis内存-->
<cache type="com.aaa.sbm.util.MyCustomCache"></cache>
优化(防止硬编码和魔法值)
配置redis集群和连接池配置都是硬编码,不方便修改,连接池配置还有魔法值,在java代码规范中都是不允许。。。
配置
#配置rabbitmq
#rabbitmq.host=
#rabbitmq.port=
#配置druid
#druid.url=
#druid.username=
# redis连接池配置
#spirngboot+mybatis连接redis cluster配置
#最大能够保持空闲状态的链接数
redis.maxIdle=2000
#最大连接数
redis.maxTotal=20000
#最大的等待时长 毫秒
redis.maxWaitMillis=20000
#当调用borrow Object方法时,是否进行有效性检查
redis.testOnBorrow=false
redis.testOnReturn=false
#集群节点配置
redis.nodes=192.168.170.21:8001,192.168.170.21:8002,192.168.170.22:8003,192.168.170.22:8004,192.168.170.23:8005,192.168.170.23:8006
#企业中配置会更多 更深入的了解 配置,优化企业中实战使用
编写类
package com.aaa.sbm.property;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @FileName: RedisProperity
* @Description:
* @Author: zhz
* @CreateTime: 2024/12/5 11:04
* @Version: 1.0.0
*/
@Component
@PropertySource("project.properties") //指定对应配置文件名称
@ConfigurationProperties(prefix = "redis") //配置前缀为redis的
@Data
public class RedisProperty {
//最大能够保持空闲状态的链接数
private int maxIdle;
//最大连接数
private int maxTotal;
//最大的等待时长 毫秒
private int maxWaitMillis;
//当调用borrow Object方法时,是否进行有效性检查
private Boolean testOnBorrow;
private Boolean testOnReturn;
//集群节点配置
private String nodes;
}
标签:缓存,redis,192.168,connection,key,import
From: https://www.cnblogs.com/xiaomubupi/p/18639413