SpringBoot-Redis联合Mybatis实现分布式缓存

    科技2026-02-16  8

    SpringBoot-Redis联合Mybatis实现分布式缓存

    文章目录

    SpringBoot-Redis联合Mybatis实现分布式缓存相关依赖配置文件缓存实体类Mybatis Dao & MapperRedisCache.java:Test.java

    相关依赖

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency>

    配置文件

    关于Redis的主从复制、哨兵、集群的配置:Redis搭建主从复制、哨兵集群

    spring.redis.host= [你redis服务所在的主机ip] spring.redis.port=[你redis服务端口 单机一般是6379] # 单机配置 #spring.redis.database=1 #server.port=8899 #如果redis采用哨兵机制,改成连接哨兵的方式 #sentinel为配置文件中自定的master节点名称 spring.redis.sentinel.master=mymaster #如果有多个哨兵(集群) 则配置各自的节点地址 ip + 端口 spring.redis.sentinel.nodes=[你redis服务所在的主机ip]:[哨兵端口 单个的话一般是26379] #数据源配置 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=root #用 / 会报错 mybatis.mapper-locations=classpath:com.junsir.mapper/*.xml mybatis.type-aliases-package=com.junsir.entity #打印数据库的操作 logging.level.com.junsir.dao=debug

    缓存实体类

    这是我们要向Redis中缓存的对象

    @Data @Accessors(chain = true) public class Person implements Serializable { private String personId; private String name; private Integer gender; private String personAddr; private Date birthday; }

    Mybatis Dao & Mapper

    定义了一个方法 返回所有Person对象,假设我们的缓存生效,将无法看到查询数据库的操作日志,而是显示Cache hit表示击中缓存

    public interface PersonDao { List<Person> findAll(); }

    Mapper:

    直接启用Mybatis的<-cache>标签,缓存是本机缓存,所以我们需要实现自定义Redis缓存

    <mapper namespace="com.junsir.dao.PersonDao"> <!-- 开启二级缓存 需要entity开启序列化 type指定自定义缓存策略 --> <cache type="com.junsir.cache.RedisCache"/> <!-- 关联查询时,需要保证各方缓存的数据都是最新的,采用共享缓存方案 --> <!-- <cache-ref namespace="com.junsir.dao.PersonDao"/>--> <!-- findAll --> <select id="findAll" resultType="Person"> select person_id,name,gender from person </select> </mapper>

    RedisCache.java:

    此类需要实现org.apache.ibatis.cache.Cache接口,才可以在Mapper中进行指定

    /** * 本类由mybatis初始化 启动时并无法由spring容器管理(盲猜参数无法传递id),故无法注入拿到RedisTemplate * 要拿到RedisTemplate 需要动下工厂 在工厂启动时拿到RedisTemplate * * 实现细节: * 多表关联查询下的内容保持最新 - 由于DB增删改只会使Redis清空对应key的缓存 所以目的就是让有关联的缓存数据同时进同时出 * * 实现完毕之后的优化问题: * 1.key过长会影响redis性能,采用MD5算法对key进行处理,这里利用的是MD5加密算法的唯一性 * */ public class RedisCache implements Cache { //自定义Cache必要条件 private final String id; //根据断点 : id:mapper的namespace public RedisCache(String id) { this.id = id; } //返回cache的唯一标识 @Override public String getId() { return this.id; } //重点实现 加入缓存 @Override public void putObject(Object key, Object value) { System.out.println("key================" + key + "value ===================" + value); RedisTemplate redisTemplate = getRedisTemplate(); redisTemplate.opsForHash().put(id.toString(),keyToMd5(key.toString()),value); } //重点实现 查询缓存 @Override public Object getObject(Object key) { System.out.println("key================" + key ); RedisTemplate redisTemplate = getRedisTemplate(); return redisTemplate.opsForHash().get(id.toString(),keyToMd5(key.toString())); } //根据指定的key删除缓存 目前没有实现 @Override public Object removeObject(Object o) { return null; } //清空缓存 执行增删改的时候都会进行clear @Override public void clear() { RedisTemplate redisTemplate = getRedisTemplate(); //清空缓存 redisTemplate.delete(id.toString()); } //计算缓存数量 @Override public int getSize() { RedisTemplate redisTemplate = getRedisTemplate(); //获取哈希中的键值对数量 return redisTemplate.opsForHash().size(id.toString()).intValue(); } //统一加工redisTemplate 并返回 public RedisTemplate getRedisTemplate(){ //获取redisTemplate RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate"); //设置序列化策略 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); return redisTemplate; } //优化: 对key做MD5处理 public String keyToMd5(String key){ return DigestUtils.md5DigestAsHex(key.getBytes()); } }

    Test.java

    在确保Redis服务正常启动后,运行以下测试程序

    @SpringBootTest(classes = RedisApplication.class) public class TestPersonService { @Autowired private PersonService personService; @Test public void test(){ //理想状态下 第一次查询 Redis中无相关数据 personService.findAll().forEach(p-> System.out.println("p==" + p)); System.out.println("==============================="); //理想状态下 第一次查询的结果已经存在于Redis 此时查询不会再经过数据库 personService.findAll().forEach(p-> System.out.println("p==" + p)); } }

    Processed: 0.016, SQL: 9