SpringBoot+Mybatis使用Redis作为二级缓存实现与解决删除/修改/新增无法更新缓存【调用clear()方法】的问题。

5 篇文章 0 订阅
4 篇文章 0 订阅

SpringBoot+Mybatis使用Redis作为二级缓存实现与解决删除/修改/新增无法更新缓存【调用clear方法】的问题。

一. 搭建环境

  1. 配置Maven。
  2. SpringBoot整合Redis。
  3. SpringBoot整合Mybatis。

pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.5.6</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zhao</groupId>
    <artifactId>Redis</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <jedis.version>4.0.0-beta4</jedis.version>
        <junit.version>4.13.1</junit.version>
        <spring.boot.starter.data.redis>2.5.4</spring.boot.starter.data.redis>
        <lombok.version>1.18.20</lombok.version>
        <mybatis.spring.boot.starter>2.2.0</mybatis.spring.boot.starter>
        <druid.spring.boot.starter>1.2.5</druid.spring.boot.starter>
        <mysql.connect.java>8.0.26</mysql.connect.java>
    </properties>
    
    <modules>
        <module>01-Jedis</module>
        <module>02-SpringBoot-Redis</module>
        <module>03-Mybatis-Redis</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>${jedis.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <version>${spring.boot.starter.data.redis}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.starter}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.spring.boot.starter}</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.connect.java}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

配置文件application.yaml如下:

server:
  port: 8809
spring:
  redis:
    database: 0
    port: 6379
    host: localhost
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      url: jdbc:mysql://localhost:3306/demo?characterEncoding=UTF-8
      username: root
      password: 123
      driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.zhao.entity
  configuration:
    cache-enabled: true
logging:
  level:
    com:
      zhao:
        dao: debug

二.获取Redis客户端的工具类

这里使用的是RedisTemplate作为操作Redis的客户端。

package com.zhao.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

//获取SpringBoot创建好的工厂
@Configuration
@Slf4j
public class ApplicationContextUtils implements ApplicationContextAware {

    //保留下来的工厂
    private static ApplicationContext applicationContext;

    //将创建好的工厂以参数形式传递给这个类
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    //提供在工厂中获取对象的方法
    //RedisTemplate redisTemplate
    public static Object getBean(String beanName) {
        if (beanName == null && beanName.equals(" ")) {
            return null;
        }
        return applicationContext.getBean(beanName);
    }
}

三. 自定义Redis缓存类,实现Cache接口。

注意点: 1.必须要有一个字符串成员变量。2.必须要有一个构造方法为这个成员变量传值。3.pojo/entity对象必须实现序列化接口。

package com.zhao.cache;

import com.zhao.util.ApplicationContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.concurrent.locks.ReadWriteLock;

@Slf4j
public class RedisCache implements Cache {

    private final String id;

    public RedisCache(String id) {
        if (id == null) {
           throw new IllegalArgumentException("Cache instances require an ID");
        }
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object key, Object value) {
        //使用redis中的hash类型作为缓存的存储类型
        getRedisTemplate().opsForHash().put(id.toString(), key.toString(), value);
        log.info("查询结果存入缓存:id:{} key:{} value:{}", id.toString(), key.toString(), value.toString());
    }

    @Override
    public Object getObject(Object key) {
        //获取存储的数据
        Object value = getRedisTemplate().opsForHash().get(id.toString(), key.toString());
        log.info("取到缓存内容:{}", value);
        return value;
    }

    @Override
    public Object removeObject(Object key) {
        log.info("执行removeObject方法移除缓存。");
        getRedisTemplate().opsForHash().delete(id, key.toString());
        return null;
    }

    @Override
    public void clear() {
        log.info("执行clear方法清空缓存。");
        getRedisTemplate().delete(id.toString());//清空缓存
    }

    @Override
    public int getSize() {
        //获取hash中的key-value的数量
        int num = getRedisTemplate().opsForHash().size(id).intValue();
        log.info("获取缓存中键值对的数量:", num);
        return num;
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return null;
    }

    //封装redisTemplate
    private RedisTemplate getRedisTemplate() {
        //获取redisTemplate
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}
  • getId(): 获得Id值。这个Id值与namespace相同。
  • putObject(Object key, Object value): 将查询出来的值存入缓存。由于键和值均是对象我们选用redisTemplate作为操作Redis的客户端,采用hash类型的数据存储缓存的值。key对应成员变量id、hkey对应方法参数 Object key、hvalue对应方法参数Object value。
  • getObject(Object key): 根据key获取value。
  • removeObject(Object key): Mybatis中的保留方法,只有在回退的时候才会调用,可以不予实现。
  • clear(): update/delete/insert更新缓存时底层调用的是这个方法。这里我实现的是根据成员变量id来删除当前命名空间下的缓存。
  • getReadWriteLock(): 读写锁来保持同步,可以不予实现。
  • getRedisTemplate(): 这是我们自己添加的方法,不是Cache接口中的方法。通过使用该方法获取ApplicationContext中的RedisTemplate对象。此外key和hkey不需要存储对象,仅存储字符串就可以。所以我设置了key和hkey使用StringRedisSerializer,不使用默认的JDK序列化器。

四.开启二级缓存,设置缓存

这里使用xml方式

    <!--开启mybatis的二级缓存-->
    <cache type="com.zhao.cache.RedisCache"/>

五.特别注意点

如果在server层中添加了事务控制,如果在更新/删除/新增类型的方法上添加了@Transactional(propagation = Propagation.SUPPORTS)或者@Transactional(propagation = Propagation.NOT_SUPPORTED)注解,那么更新/删除/新增不会调用缓冲类中的clear()方法,Redis中的缓存也无法清除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值