SpringBoot整合MP通過(guò)Redis實(shí)現(xiàn)二級(jí)緩存方式
一級(jí)緩存與二級(jí)緩存
- 一級(jí)緩存是SqlSession級(jí)別的緩存。在操作數(shù)據(jù)庫(kù)時(shí)需要構(gòu)造sqlSession對(duì)象,在對(duì)象中有一個(gè)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲(chǔ)緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。 一級(jí)緩存是默認(rèn)開(kāi)啟的
- 二級(jí)緩存是namespace級(jí)別的緩存,多個(gè)SqlSession去操作同一個(gè)Mapper的sql語(yǔ)句,多個(gè)SqlSession可以共用二級(jí)緩存,二級(jí)緩存是跨SqlSession的
因?yàn)樵赟pring與Mybatis整合后,Mybatis的一級(jí)緩存是不能使用的,所以我們一般實(shí)現(xiàn)Mybatis的二級(jí)緩存,而在集群環(huán)境下,Mybatis的二級(jí)緩存只能實(shí)現(xiàn)單個(gè)節(jié)點(diǎn)的緩存,所以我們采用分布式的二級(jí)緩存,這里使用的是Redis的實(shí)現(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
在啟動(dòng)類上添加@EnableCaching注解
EnableCaching:?jiǎn)?dòng)緩存功能
開(kāi)啟緩存功能,配置類中需要加上這個(gè)注解,有了這個(gè)注解以后,spring才知道你需要使用緩存的功能,其他的和緩存相關(guān)的注解才會(huì)有效,spring中主要是通過(guò)aop實(shí)現(xiàn)的,通過(guò)aop來(lái)攔截需要使用緩存的方法,實(shí)現(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二級(jí)緩存的Cache接口的實(shí)現(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實(shí)現(xiàn)Mybatis Plus二級(jí)緩存 * */ @Slf4j public class MybatisRedisCache implements Cache { // 讀寫鎖 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); private RedisTemplate redisTemplate; private RedisTemplate getRedisTemplate(){ //通過(guò)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類型進(jìn)行存儲(chǔ) 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("緩存出錯(cuò) "); } 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; } }
因?yàn)镽edisTemplate的實(shí)例化需要使用Spring的工廠進(jìn)行創(chuàng)建,而我們創(chuàng)建的MybatisRedisCache類實(shí)現(xiàn)的是Mybatis的Cache接口,所以這個(gè)類不是由工廠進(jìn)行管理的,所以我們不能直接在該類中直接使用注解注入RedisTemplate,所以我們創(chuàng)建一個(gè)獲取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 獲取實(shí)例 public static Object getBeanByName(String beanName) { if (beanName == null || applicationContext == null) { return null; } return applicationContext.getBean(beanName); } //只適合一個(gè)class只被定義一次的bean(也就是說(shuō),根據(jù)class不能匹配出多個(gè)該class的實(shí)例) public static Object getBeanByType(Class clazz) { if (clazz == null || applicationContext == null) { return null; } return applicationContext.getBean(clazz); } public static String[] getBeanDefinitionNames() { return applicationContext.getBeanDefinitionNames(); } }
實(shí)現(xiàn)ApplicationContextAware接口后,在Spring Boot啟動(dòng)創(chuàng)建工廠后,就會(huì)自動(dòng)調(diào)用這個(gè)接口的setApplicationContext方法,將創(chuàng)建的工廠以參數(shù)的形式傳遞給這個(gè)類,在這個(gè)方法中我們就可以把工廠給保存下來(lái)。
最后我們只需要在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é)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot結(jié)合Redis實(shí)現(xiàn)緩存管理功能
- SpringBoot整合redis使用緩存注解詳解
- springboot使用redis注解做緩存的基本操作方式
- SpringBoot中Redis的緩存更新策略詳解
- springboot整合ehcache和redis實(shí)現(xiàn)多級(jí)緩存實(shí)戰(zhàn)案例
- SpringBoot結(jié)合Redis實(shí)現(xiàn)緩存
- SpringBoot使用Redis實(shí)現(xiàn)分布式緩存
- SpringBoot中的Redis?緩存問(wèn)題及操作方法
- SpringBoot淺析緩存機(jī)制之Redis單機(jī)緩存應(yīng)用
- SpringBoot整合Redis實(shí)現(xiàn)token緩存
相關(guān)文章
java根據(jù)不同的參數(shù)調(diào)用不同的實(shí)現(xiàn)類操作
這篇文章主要介紹了java根據(jù)不同的參數(shù)調(diào)用不同的實(shí)現(xiàn)類操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09springcloud安裝rabbitmq并配置延遲隊(duì)列插件的過(guò)程詳解
本期主要講解如何利用docker快速安裝rabbitmq并且配置延遲隊(duì)列插件,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05SpringBoot的@RestControllerAdvice作用詳解
這篇文章主要介紹了SpringBoot的@RestControllerAdvice作用詳解,@RestContrllerAdvice是一種組合注解,由@ControllerAdvice,@ResponseBody組成,本質(zhì)上就是@Component,需要的朋友可以參考下2024-01-01Springboot打包為Docker鏡像并部署的實(shí)現(xiàn)
這篇文章主要介紹了Springboot打包為Docker鏡像并部署的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12SpringBoot接口正確接收時(shí)間參數(shù)的幾種方式
這篇文章主要給大家介紹了關(guān)于SpringBoot接口正確接收時(shí)間參數(shù)的相關(guān)資料,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用springboot具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09