SpringBoot與redis
核心步驟
-
使用前準(zhǔn)備
打開redis
-
配置redis(spring.redis.host=127.0.0.1)
如果是在虛擬機(jī)中使用:
docker pull redis
docker run -d -p 6379:6379 --name myredis redis(鏡像名)
創(chuàng)建springboot的時(shí)候選擇web,mysql,mybatis,redis模塊(默認(rèn)使用RedisCacheConfiguration)
導(dǎo)入數(shù)據(jù)庫(kù)文件創(chuàng)建出department和employee表
創(chuàng)建javaBean封裝數(shù)據(jù)
整合Mybatis操作數(shù)據(jù)庫(kù)(掃描com.atguigu.cache.mapper和配置數(shù)據(jù)源)
-
快速使用
package com.atguigu.cache.springboot2; import com.atguigu.cache.bean.Employee; import com.atguigu.cache.mapper.EmployeeMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class Springboot2cacheApplicationTests { @Autowired EmployeeMapper employeeMapper; //導(dǎo)入了redis的start就可以將redisTemplate和stringRedisTemplate自動(dòng)注入 @Autowired RedisTemplate redisTemplate自動(dòng)注入; //操作k-v都是對(duì)象 @Autowired StringRedisTemplate stringRedisTemplate; //操作k-v都是字符串的,因?yàn)檫@種類型比較多所以redis封裝了一個(gè) @Test public void contextLoads() { Employee empById = employeeMapper.getEmpById(1); //默認(rèn)如果保存對(duì)象蔗蹋,使用jdk序列化機(jī)制,序列化后的數(shù)據(jù)保存到redis中,JdkSerializationRedisSerializer是默認(rèn)序列化方式 //redisTemplate.opsForValue().set("emp-01",empById); //1、將數(shù)據(jù)以json的方式保存 //(1)自己將對(duì)象轉(zhuǎn)為json //(2)redisTemplate默認(rèn)的序列化規(guī)則;改變默認(rèn)的序列化規(guī)則;自己寫一個(gè)redisTemplate redisTemplate.opsForValue().set("emp-01",empById); } }
-
序列化方式的研究
- JdkSerializationRedisSerializer是默認(rèn)序列化方式辫秧,是最簡(jiǎn)單的也是最安全的,只要實(shí)現(xiàn)了Serializer接口,實(shí)體類型不翩,集合,Map等都能序列化與反序列化麻裳,但缺陷是序列化數(shù)據(jù)很多口蝠,會(huì)對(duì)redis造成更大壓力,且可讀性和跨平臺(tái)基本無(wú)法實(shí)現(xiàn)
- Jackson2JsonRedisSerializer用的是json的序列化方式津坑,能解決JdkSerializationRedisSerializer帶來的缺陷妙蔗,但復(fù)雜類型(集合,泛型,實(shí)體包裝類)反序列化時(shí)會(huì)報(bào)錯(cuò),且Jackson2JsonRedisSerializer需要指明序列化的類Class疆瑰,這代表一個(gè)實(shí)體類就有一個(gè)RedisCacheManager眉反,代碼冗余
- 最后查看源碼昙啄,發(fā)現(xiàn)RedisSerializer(Jackson2JsonRedisSerializer也實(shí)現(xiàn)此接口)的實(shí)現(xiàn)類中有一個(gè)GenericJackson2JsonRedisSerializer,此類不用需要指明序列化的類寸五,寫一個(gè)RedisCacheManager即可梳凛,代碼更精簡(jiǎn),復(fù)雜類型(集合,泛型)反序列化時(shí)不會(huì)報(bào)錯(cuò)播歼,查看redis數(shù)據(jù)可以發(fā)現(xiàn)實(shí)現(xiàn)原理是在json數(shù)據(jù)中放一個(gè)@class屬性伶跷,指定了類的全路徑包名,方便反序列化秘狞,所以在內(nèi)存占用上高一點(diǎn)點(diǎn)叭莫,但是反序列化性能自測(cè)要比Jackson2JsonRedisSerializer高(有興趣的老哥也可以自己試試性能差別),空間換時(shí)間烁试,當(dāng)然也因?yàn)榇颂匦怨统酰?xiàng)目一部分的結(jié)構(gòu)(實(shí)體全類名)會(huì)json數(shù)據(jù)中體現(xiàn)。
注:經(jīng)過反復(fù)考慮减响,目前使用了GenericJackson2JsonRedisSerializer作為序列化方式
-
改變序列化方式
- 使用Jackson2JsonRedisSerializer序列化
package com.atguigu.cache.config;
import com.atguigu.cache.bean.Department;
import com.atguigu.cache.bean.Employee;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.net.UnknownHostException;
import java.time.Duration;
@Configuration
public class MyRedisConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer
(new Jackson2JsonRedisSerializer<Employee>(Employee.class)));
return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();
}
}
- 使用GenericJackson2JsonRedisSerializer序列化
//springboot檢查到了緩存管理器,就不會(huì)使用默認(rèn)的緩存管理器了,會(huì)使用我們?cè)谙旅鎰?chuàng)建的緩存管理器
//有多個(gè)CacheManager需要用注解@Primary //將某個(gè)緩存管理器作為默認(rèn)的
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new
GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();
}
測(cè)試
//可以在注解中指定cacheManager,cacheManager = "cacheManager",這個(gè)cacheManager是上面的方法名
@Cacheable(cacheNames = "dept")
public Department getDeptById(Integer id){
System.out.println("查詢部門"+id);
Department department = departmentMapper.getDeptById(id);
return department;
}
三靖诗、整合redis作為緩存
- Redis 是一個(gè)開源(BSD許可)的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng)支示,它可以用作數(shù)據(jù)庫(kù)刊橘、緩存和消息中間件。
- 1颂鸿、安裝redis:使用docker促绵;
- 2、引入redis的starter
- 3嘴纺、配置redis
- 4败晴、測(cè)試緩存
- 原理:CacheManager===Cache 緩存組件來實(shí)際給緩存中存取數(shù)據(jù)
- 1)、引入redis的starter栽渴,容器中保存的是 RedisCacheManager尖坤;
- 2)、RedisCacheManager 幫我們創(chuàng)建 RedisCache 來作為緩存組件闲擦;RedisCache通過操作redis緩存數(shù)據(jù)的
- 3)慢味、默認(rèn)保存數(shù)據(jù) k-v 都是Object;利用序列化保存墅冷;如何保存為json
- 1纯路、引入了redis的starter,cacheManager變?yōu)?RedisCacheManager俺榆;
- 2、默認(rèn)創(chuàng)建的 RedisCacheManager 操作redis的時(shí)候使用的是 RedisTemplate<Object, Object>
- 3装哆、RedisTemplate<Object, Object> 是 默認(rèn)使用jdk的序列化機(jī)制
- 4)罐脊、自定義CacheManager定嗓;
@MapperScan("com.atguigu.cache.mapper")
@SpringBootApplication
@EnableCaching
public class Springboot2Application {
public static void main(String[] args) {
SpringApplication.run(Springboot2Application.class, args);
}
}