mybatis-plus使用redis作为二级缓存

42次阅读

共计 4630 个字符,预计需要花费 12 分钟才能阅读完成。

建议缓存放到 service 层,你可以自定义自己的 BaseServiceImpl 重写注解父类方法,继承自己的实现。为了方便,这里我们将缓存放到 mapper 层。mybatis-plus 整合 redis 作为二级缓存与 mybatis 整合 redis 略有不同。

1. mybatis-plus 开启二级缓存

mybatis-plus.configuration.cache-enabled=true

2. 定义 RedisTemplate 的 bean 交给 spring 管理,这里为了能将对象直接存取到 redis 中,进行了一些序列化的操作

@Bean(value = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        //Use Jackson 2Json RedisSerializer to serialize and deserialize the value of redis (default JDK serialization)
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 将类名称序列化到 json 串中
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 设置输入时忽略 JSON 字符串中存在而 Java 对象实际没有的属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        //Use String RedisSerializer to serialize and deserialize the key value of redis
        RedisSerializer redisSerializer = new StringRedisSerializer();
        //key
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        //value
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;

    }

3. 自定义自己的缓存管理

package com.qctchina.headsetserver.config;

import com.qctchina.headsetserver.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author shuangyueliao
 * @create 2019/9/10 14:02
 * @Version 0.1
 */
@Slf4j
public class MybatisRedisCache implements Cache {


    // 读写锁
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

    // 这里使用了 redis 缓存,使用 springboot 自动注入
    private RedisTemplate<String, Object> redisTemplate;

    private String id;

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

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

    @Override
    public void putObject(Object key, Object value) {if (redisTemplate == null) {
            // 由于启动期间注入失败,只能运行期间注入,这段代码可以删除
            redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
        }
        if (value != null) {redisTemplate.opsForValue().set(key.toString(), value);
        }
    }

    @Override
    public Object getObject(Object key) {if (redisTemplate == null) {
            // 由于启动期间注入失败,只能运行期间注入,这段代码可以删除
            redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
        }
        try {if (key != null) {return redisTemplate.opsForValue().get(key.toString());
            }
        } catch (Exception e) {e.printStackTrace();
            log.error("缓存出错");
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {if (redisTemplate == null) {
            // 由于启动期间注入失败,只能运行期间注入,这段代码可以删除
            redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
        }
        if (key != null) {redisTemplate.delete(key.toString());
        }
        return null;
    }

    @Override
    public void clear() {log.debug("清空缓存");
        if (redisTemplate == null) {redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
        }
        Set<String> keys = redisTemplate.keys("*:" + this.id + "*");
        if (!CollectionUtils.isEmpty(keys)) {redisTemplate.delete(keys);
        }
    }

    @Override
    public int getSize() {if (redisTemplate == null) {
            // 由于启动期间注入失败,只能运行期间注入,这段代码可以删除
            redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
        }
        Long size = redisTemplate.execute((RedisCallback<Long>) RedisServerCommands::dbSize);
        return size.intValue();}

    @Override
    public ReadWriteLock getReadWriteLock() {return this.readWriteLock;}
}

SpringUtil 是手动获取 bean 的工具类

@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtil.applicationContext = applicationContext;}

    public static Object getBean(String name){return applicationContext.getBean(name);
    }

    public static <T> T getBean(String name, Class<T> clazz){return applicationContext.getBean(name, clazz);
    }

    public static <T> T getBean(Class<T> clazz){return applicationContext.getBean(clazz);
    }
}

4. 在 mapper 上加上注解 @CacheNamespace

@CacheNamespace(implementation= MybatisRedisCache.class,eviction=MybatisRedisCache.class)
public interface CommonMapper extends BaseMapper<Common> {

如果调用该 mapper 下的方法,那么会使用 redis 缓存

正文完
 0