SpringBoot整合MP通過Redis實現(xiàn)二級緩存方式
一級緩存與二級緩存
- 一級緩存是SqlSession級別的緩存。在操作數(shù)據(jù)庫時需要構造sqlSession對象,在對象中有一個數(shù)據(jù)結構(HashMap)用于存儲緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。 一級緩存是默認開啟的
- 二級緩存是namespace級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的
因為在Spring與Mybatis整合后,Mybatis的一級緩存是不能使用的,所以我們一般實現(xiàn)Mybatis的二級緩存,而在集群環(huán)境下,Mybatis的二級緩存只能實現(xiàn)單個節(jié)點的緩存,所以我們采用分布式的二級緩存,這里使用的是Redis的實現(xiàn)
配置文件
spring:
redis:
host: 127.0.0.1
port: 6379
database: 0
#配置redis
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
url: jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=UTF-8
#配置Mybatis-Plus
mybatis-plus:
mapper-locations: classpath:mybatis/mapper/*.xml
configuration:
cache-enabled: true在啟動類上添加@EnableCaching注解
EnableCaching:啟動緩存功能
開啟緩存功能,配置類中需要加上這個注解,有了這個注解以后,spring才知道你需要使用緩存的功能,其他的和緩存相關的注解才會有效,spring中主要是通過aop實現(xiàn)的,通過aop來攔截需要使用緩存的方法,實現(xiàn)緩存的功能
設置RedisTemplate
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
public class RedisConfiguration {
/**
* 設置redisTemplate
*/
@Bean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}創(chuàng)建MybatisRedisCache類重寫Mybatis二級緩存的Cache接口的實現(xiàn)
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 javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
*
* 使用redis實現(xiàn)Mybatis Plus二級緩存
*
*/
@Slf4j
public class MybatisRedisCache implements Cache {
// 讀寫鎖
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
private RedisTemplate redisTemplate;
private RedisTemplate getRedisTemplate(){
//通過ApplicationContextHolder工具類獲取RedisTemplate
if (redisTemplate == null) {
redisTemplate = (RedisTemplate) ApplicationContextHolder.getBeanByName("redisTemplate");
}
return redisTemplate;
}
private final String id;
public MybatisRedisCache(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) {
//使用redis的Hash類型進行存儲
getRedisTemplate().opsForHash().put(id,key.toString(),value);
}
@Override
public Object getObject(Object key) {
try {
//根據(jù)key從redis中獲取數(shù)據(jù)
return getRedisTemplate().opsForHash().get(id,key.toString());
} catch (Exception e) {
e.printStackTrace();
log.error("緩存出錯 ");
}
return null;
}
@Override
public Object removeObject(Object key) {
if (key != null) {
getRedisTemplate().delete(key.toString());
}
return null;
}
@Override
public void clear() {
log.debug("清空緩存");
Set<String> keys = getRedisTemplate().keys("*:" + this.id + "*");
if (!CollectionUtils.isEmpty(keys)) {
getRedisTemplate().delete(keys);
}
}
@Override
public int getSize() {
Long size = (Long) getRedisTemplate().execute((RedisCallback<Long>) RedisServerCommands::dbSize);
return size.intValue();
}
@Override
public ReadWriteLock getReadWriteLock() {
return this.readWriteLock;
}
}因為RedisTemplate的實例化需要使用Spring的工廠進行創(chuàng)建,而我們創(chuàng)建的MybatisRedisCache類實現(xiàn)的是Mybatis的Cache接口,所以這個類不是由工廠進行管理的,所以我們不能直接在該類中直接使用注解注入RedisTemplate,所以我們創(chuàng)建一個獲取Spring Boot創(chuàng)建好的工廠的ApplicationContextHolder工具類,用于獲取RedisTemplate
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHolder.applicationContext = applicationContext;
}
//根據(jù)bean name 獲取實例
public static Object getBeanByName(String beanName) {
if (beanName == null || applicationContext == null) {
return null;
}
return applicationContext.getBean(beanName);
}
//只適合一個class只被定義一次的bean(也就是說,根據(jù)class不能匹配出多個該class的實例)
public static Object getBeanByType(Class clazz) {
if (clazz == null || applicationContext == null) {
return null;
}
return applicationContext.getBean(clazz);
}
public static String[] getBeanDefinitionNames() {
return applicationContext.getBeanDefinitionNames();
}
}實現(xiàn)ApplicationContextAware接口后,在Spring Boot啟動創(chuàng)建工廠后,就會自動調用這個接口的setApplicationContext方法,將創(chuàng)建的工廠以參數(shù)的形式傳遞給這個類,在這個方法中我們就可以把工廠給保存下來。
最后我們只需要在Mapper接口上添加@CacheNamespace注解,就完成了
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chenyx.config.MybatisRedisCache;
import com.chenyx.entity.WeChatUser;
import org.apache.ibatis.annotations.CacheNamespace;
@CacheNamespace(implementation= MybatisRedisCache.class,eviction=MybatisRedisCache.class)
public interface WeChatUserListMapper extends BaseMapper<WeChatUser>{
}總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringBoot結合Redis實現(xiàn)緩存管理功能
- SpringBoot整合redis使用緩存注解詳解
- springboot使用redis注解做緩存的基本操作方式
- SpringBoot中Redis的緩存更新策略詳解
- springboot整合ehcache和redis實現(xiàn)多級緩存實戰(zhàn)案例
- SpringBoot結合Redis實現(xiàn)緩存
- SpringBoot使用Redis實現(xiàn)分布式緩存
- SpringBoot中的Redis?緩存問題及操作方法
- SpringBoot淺析緩存機制之Redis單機緩存應用
- SpringBoot整合Redis實現(xiàn)token緩存
相關文章
基于Java實現(xiàn)簡易的局域網(wǎng)對話系統(tǒng)
這篇文章主要介紹了基于Java實現(xiàn)的簡易的局域網(wǎng)對話系統(tǒng),文中的示例代碼對我們學習Java有一定的幫助,感興趣的小伙伴快來跟隨小編一起學習一下吧2021-12-12
Java編程實現(xiàn)比對兩個文本文件并標記相同與不同之處的方法
這篇文章主要介紹了Java編程實現(xiàn)比對兩個文本文件并標記相同與不同之處的方法,涉及java針對文本文件的讀取、遍歷、判斷等相關操作技巧,需要的朋友可以參考下2017-10-10
解決JAVA非對稱加密不同系統(tǒng)加密結果不一致的問題
這篇文章主要介紹了解決JAVA非對稱加密不同系統(tǒng)加密結果不一致的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10

