SpringBoot整合MP通過Redis實現(xiàn)二級緩存方式
一級緩存與二級緩存
- 一級緩存是SqlSession級別的緩存。在操作數(shù)據(jù)庫時需要構(gòu)造sqlSession對象,在對象中有一個數(shù)據(jù)結(jié)構(gòu)(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才知道你需要使用緩存的功能,其他的和緩存相關(guān)的注解才會有效,spring中主要是通過aop實現(xiàn)的,通過aop來攔截需要使用緩存的方法,實現(xiàn)緩存的功能
設(shè)置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 { /** * 設(shè)置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)建工廠后,就會自動調(diào)用這個接口的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>{ }
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringBoot結(jié)合Redis實現(xiàn)緩存管理功能
- SpringBoot整合redis使用緩存注解詳解
- springboot使用redis注解做緩存的基本操作方式
- SpringBoot中Redis的緩存更新策略詳解
- springboot整合ehcache和redis實現(xiàn)多級緩存實戰(zhàn)案例
- SpringBoot結(jié)合Redis實現(xiàn)緩存
- SpringBoot使用Redis實現(xiàn)分布式緩存
- SpringBoot中的Redis?緩存問題及操作方法
- SpringBoot淺析緩存機制之Redis單機緩存應(yīng)用
- SpringBoot整合Redis實現(xiàn)token緩存
相關(guān)文章
java根據(jù)不同的參數(shù)調(diào)用不同的實現(xiàn)類操作
這篇文章主要介紹了java根據(jù)不同的參數(shù)調(diào)用不同的實現(xiàn)類操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09springcloud安裝rabbitmq并配置延遲隊列插件的過程詳解
本期主要講解如何利用docker快速安裝rabbitmq并且配置延遲隊列插件,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05SpringBoot的@RestControllerAdvice作用詳解
這篇文章主要介紹了SpringBoot的@RestControllerAdvice作用詳解,@RestContrllerAdvice是一種組合注解,由@ControllerAdvice,@ResponseBody組成,本質(zhì)上就是@Component,需要的朋友可以參考下2024-01-01Springboot打包為Docker鏡像并部署的實現(xiàn)
這篇文章主要介紹了Springboot打包為Docker鏡像并部署的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12SpringBoot接口正確接收時間參數(shù)的幾種方式
這篇文章主要給大家介紹了關(guān)于SpringBoot接口正確接收時間參數(shù)的相關(guān)資料,文中通過代碼示例介紹的非常詳細,對大家學(xué)習(xí)或者使用springboot具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09