redis-3

缓存流程图

缓存实战
准备工作
复制项目,修改名称
引入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;

}

posted on   小木不痞  阅读(4)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示