04.SpringBoot中集成Redis缓存
1、依赖
1.1、pom.xml
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
1.2、application.yaml
spring:
redis:
host: 127.0.0.1 # Redis服务器地址
database: 0 # Redis数据库索引(默认为0)
port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码(默认为空)
jedis:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
timeout: 3000ms # 连接超时时间(毫秒)
1.3、RedisConfig
package com.wnx.mall.tiny.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* @author by wangnaixing
* @Description
* @Date 2022/1/16 13:27
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisSerializer<Object> serializer = redisSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisSerializer<Object> redisSerializer() {
//创建JSON序列化器
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
return serializer;
}
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//设置Redis缓存有效期为1天
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1));
return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
}
2、集成
2.1、ReidsService
package com.wnx.mall.tiny.service;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author by wangnaixing
* @Description
* @Date 2022/1/16 13:29
*/
public interface RedisService {
/**
* 保存属性
* @param key
* @param value
* @param time
*/
void set(String key,Object value,long time);
/**
* 保存属性
* @param key
* @param value
*/
void set(String key,Object value);
/**
* 获取属性
* @param key
* @return
*/
Object get(String key);
/**
* 删除属性
* @param key
* @return
*/
Boolean del(String key);
/**
* 批量删除属性
* @param keys
* @return
*/
Long del(List<String> keys);
/**
* 设置过期时间
* @param key
* @param time
* @return
*/
Boolean expire(String key,long time);
/**
* 判断是否有该属性
* @param key
* @return
*/
Boolean hasKey(String key);
/**
* 按delta递增
* @param key
* @param delta
* @return
*/
Long incr(String key,long delta);
/**
* 按照delta值递减
* @param key
* @param delta
* @return
*/
public Long decr(String key, long delta);
/**
* 获取Hash结构中的属性
* @param key
* @param hashKey
* @return
*/
Object hGet(String key,String hashKey);
/**
* 向Hash结构中放入一个属性
* @param key
* @param hashKey
* @param value
* @param time
* @return
*/
Boolean hSet(String key,String hashKey,Object value,long time);
/**
* 直接设置整个Hash结构
* @param key
* @param map
* @param time
* @return
*/
Boolean hSetAll(String key, Map<String,Object> map, long time);
/**
* 删除Hash结构中的属性
* @param key
* @param hashKey
*/
void hDel(String key,Object...hashKey);
/**
* 判断Hash结构中是否有该属性
* @param key
* @param hashKey
* @return
*/
Boolean hHashKey(String key,String hashKey);
/***
* Hash结构中的属性递增
* @param key
* @param hashKey
* @param delta
* @return
*/
Long hIncr(String key,String hashKey,Long delta);
/**
* Hash结构中属性递减
* @param key
* @param hashKey
* @param delta
* @return
*/
Long hDecr(String key,String hashKey,Long delta);
/**
* 获取Set结构
* @param key
* @return
*/
Set<Object> sMembers(String key);
/**
* 向Set结构中添加属性
* @param key
* @param value
* @return
*/
Long sAdd(String key,Object...value);
/**
* 是否为Set中属性
* @param key
* @param value
* @return
*/
Boolean sIsMember(String key,Object value);
/**
* 获取Set结构的长度
* @param key
* @return
*/
Long sSize(String key);
/**
* 删除Set结构中的属性
* @param key
* @param values
* @return
*/
Long sRemove(String key,Object...values);
}
2.2、RedisServiceImpl
package com.wnx.mall.tiny.service.impl;
import com.wnx.mall.tiny.service.RedisService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author by wangnaixing
* @Description
* @Date 2022/1/16 13:29
*/
@Service
public class RedisServiceImpl implements RedisService {
@Resource
private RedisTemplate<String,Object> redisTemplate;
@Override
public void set(String key, Object value, long time) {
redisTemplate.opsForValue().set(key,value,time, TimeUnit.SECONDS);
}
@Override
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key,value);
}
@Override
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
@Override
public Boolean del(String key) {
return redisTemplate.delete(key);
}
@Override
public Long del(List<String> keys) {
return redisTemplate.delete(keys);
}
@Override
public Boolean expire(String key, long time) {
return redisTemplate.expire(key,time,TimeUnit.SECONDS);
}
@Override
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
@Override
public Long incr(String key, long delta) {
return redisTemplate.opsForValue().increment(key,delta);
}
@Override
public Long decr(String key, long delta) {
return redisTemplate.opsForValue().increment(key,-delta);
}
@Override
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key,hashKey);
}
@Override
public Boolean hSet(String key, String hashKey, Object value, long time) {
redisTemplate.opsForHash().put(key,hashKey,value);
return expire(key,time);
}
@Override
public Boolean hSetAll(String key, Map<String, Object> map, long time) {
redisTemplate.opsForHash().putAll(key,map);
return expire(key,time);
}
@Override
public void hDel(String key, Object... hashKey) {
redisTemplate.opsForHash().delete(key,hashKey);
}
@Override
public Boolean hHashKey(String key, String hashKey) {
return redisTemplate.opsForHash().hasKey(key,hashKey);
}
@Override
public Long hIncr(String key, String hashKey, Long delta) {
return redisTemplate.opsForHash().increment(key,hashKey,delta);
}
@Override
public Long hDecr(String key, String hashKey, Long delta) {
return redisTemplate.opsForHash().increment(key,hashKey,-delta);
}
@Override
public Set<Object> sMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
@Override
public Long sAdd(String key, Object... values) {
return redisTemplate.opsForSet().add(key,values);
}
@Override
public Boolean sIsMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key,value);
}
@Override
public Long sSize(String key) {
return redisTemplate.opsForSet().size(key);
}
@Override
public Long sRemove(String key, Object... values) {
return redisTemplate.opsForSet().remove(key,values);
}
}
3、测试
package com.wnx.mall.tiny.service;
import cn.hutool.core.bean.BeanUtil;
import com.wnx.mall.tiny.common.api.CommonPage;
import com.wnx.mall.tiny.mbg.model.PmsBrand;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author by wangnaixing
* @Description
* @Date 2022/1/16 13:38
*/
@SpringBootTest
public class RedisServiceTest {
@Resource
private RedisService redisService;
@Resource
private PmsBrandService pmsBrandService;
//测试注解的获取
@Test
public void testAnnoGet(){
PmsBrand pmsBrand = pmsBrandService.findById(1L);
// key=mall::pms:brand:1 ttl=86393
// value={"id":1,"name":"万和","firstLetter":"W","sort":0,"factoryStatus":1,"showStatus":1,"productCount":100,"productCommentCount":100,"logo":"http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg","bigPic":"","brandStory":"Victoria's Secret的故事"}
//同理,修改,删除PmsBrand的时候,会根据key去删除对应缓存!
PmsBrand pmsBrand1 = (PmsBrand) redisService.get("mall::pms:brand:1");
System.out.println(pmsBrand1);
}
//设置属性
@Test
public void set(){
PmsBrand brand = pmsBrandService.findById(1L);
redisService.set("brand:"+brand.getId(),brand);
//key=brand:1 value=brand的JSON串!
}
//设置属性并指定了时间60秒
@Test
public void set2(){
PmsBrand brand2 = pmsBrandService.findById(2L);
redisService.set("brand:"+brand2.getId(),brand2,60);
//key=brand:2 value=brand2的JSON串 ttl=60秒,会慢慢变成59 58 57 0秒的时候,会删除这个缓存,即缓存过期!
}
//取出属性
@Test
public void get(){
//redisTemplate 内部会处理,把JSON串变成Object对象,可直接强制转换得到Model
PmsBrand pmsBrand = (PmsBrand) redisService.get("brand:1");
System.out.println(pmsBrand);
//PmsBrand对象 [Hash = 1567145551, id=1, name=万和, firstLetter=W, sort=0, factoryStatus=1, showStatus=1, productCount=100, productCommentCount=100, logo=http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg, bigPic=, brandStory=Victoria's Secret的故事, serialVersionUID=1]
}
//根据Key删除属性
@Test
public void del(){
Boolean flag = redisService.del("brand:1");
System.out.println(flag);//删除成功返回 true!
}
/**
* 删除由key组成集合的属性
* @throws InterruptedException 中短异常
*/
@Test
public void delAll() throws InterruptedException {
//1.构造keys
CommonPage<PmsBrand> page = pmsBrandService.findByPage(1, 3);
List<String> keys = new ArrayList<>();
for (PmsBrand brand : page.getList()) {
redisService.set("brand:"+brand.getId(),brand);
keys.add("brand:"+brand.getId());
}
//2.休眠3秒,这时你可在redis客户端发现 这brand:1 brand:2 brand:3 的三个缓存,值为Model的JSON串!
Thread.sleep(3000);
//3.执行完毕,这三个缓存没有了!
redisService.del(keys);
}
//指定某个属性的过期时间
@Test
public void expire(){
PmsBrand brand = pmsBrandService.findById(1L);
redisService.set("brand:"+brand.getId(),brand);
//此种方式可在已经创建了该缓存后,还想指定缓存过期时间的时候使用。
redisService.expire("brand:"+brand.getId(),60);
}
//判断缓存是否存在该属性
@Test
public void hasKey(){
PmsBrand brand = pmsBrandService.findById(1L);
redisService.set("brand:"+brand.getId(),brand);
Boolean hasKey = redisService.hasKey("brand:" + brand.getId());
System.out.println("存在该属性:"+hasKey);//true
redisService.del("brand:" + brand.getId());
}
// 让属性自增一个整型值,返回自增完毕的值
@Test
public void incr(){
redisService.set("count",2);//要求存的必须是整型
Long incr = redisService.incr("count", 1);
System.out.println(incr);//3
}
//让属性自减一个整型值,返回自减完毕的值
@Test
public void decr(){
redisService.set("count",2);//要求存的必须是整型
Long incr = redisService.decr("count", 1);
System.out.println(incr);//1
}
//设置key为mall 属性名为brand 属性值为brand对象的缓存
@Test
public void hSet(){
PmsBrand brand = pmsBrandService.findById(1L);
redisService.hSet("mall:brand:"+brand.getId(),"id",brand.getId(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"name",brand.getName(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"first_letter",brand.getFirstLetter(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"sort",brand.getSort(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"factory_status",brand.getFactoryStatus(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"show_status",brand.getShowStatus(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"product_count",brand.getProductCount(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"product_comment_count",brand.getProductCommentCount(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"logo",brand.getLogo(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"big_pic",brand.getBigPic(),60*24);
redisService.hSet("mall:brand:"+brand.getId(),"brand_story",brand.getBrandStory(),60*24);
String name = (String) redisService.hGet("mall:brand:1", "name");
String logo = (String) redisService.hGet("mall:brand:"+brand.getId(), "logo");
System.out.println(name+"---"+logo);
// 我认为和string数据类型相比,我可以单独的取出来某个属性的值,而不是都是全部取出来!
// 万和 --- http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg
}
//哈希结构的批量设置
@Test
public void hSetAll(){
PmsBrand brand = pmsBrandService.findById(1L);
//转换成map的话,map中的key就是 hashkey
Map<String, Object> map = BeanUtil.beanToMap(brand);
redisService.hSetAll("mall:brand:"+brand.getId(),map,60*60);
String name = (String) redisService.hGet("mall:brand:1", "name");
Integer productCount = (Integer) redisService.hGet("mall:brand:"+brand.getId(), "productCount");
System.out.println(name+"---"+productCount);
//万和---100
}
//选择性删除哈希结构的属性
@Test
public void hDel(){
redisService.hDel("mall:brand:1","id","name");
}
//该hash结构中是否存在hashkey 是:返回true 不是:返回false
@Test
public void hHashKey(){
//上一test 已经删除了 id name
Boolean hashKey = redisService.hHashKey("mall:brand:1", "id");
Boolean hashKey1 = redisService.hHashKey("mall:brand:1", "name");
Boolean hashKey2 = redisService.hHashKey("mall:brand:1", "brandStory");
System.out.println(hashKey); //false
System.out.println(hashKey1); //false
System.out.println(hashKey2); // true
}
//hash的自增和自减
@Test
public void hIncrAndhDecr(){
//自增自减操作总是得到完成操作后的值
Integer sort = (Integer) redisService.hGet("mall:brand:1", "sort");
Long sortAdd1 = redisService.hIncr("mall:brand:1", "sort", 10L);
Long sortReduce1 = redisService.hDecr("mall:brand:1","sort",1L);
System.out.println(sort);//0 取出,初始值为0
System.out.println(sortAdd1);//10
System.out.println(sortReduce1);//9
}
//向Set结构中添加属性
@Test
public void sAdd(){
//往set集合里添加元素1,2,3,返回值为成功操作的次数,如果存在相同元素,不会添加进去。
Long sussCount = redisService.sAdd("mySet", 1, 2, 3);
System.out.println(sussCount); // 3 0 第二次执行,返回0
}
//是否为Set集合中元素 ,如果是:返回true 如果不是:返回false
@Test
public void sIsMember(){
Boolean flag = redisService.sIsMember("mySet", 1);
Boolean flag2 = redisService.sIsMember("mySet", 4);
System.out.println(flag);//true
System.out.println(flag2); //false
}
//返回Set集合长度
@Test
public void sSize(){
Long length = redisService.sSize("mySet");
System.out.println(length);//3
}
//删除Set集合中某个元素
@Test
public void sRemove(){
Long length = redisService.sSize("mySet"); //3
redisService.sRemove("mySet",1,2);
length = redisService.sSize("mySet");
System.out.println(length);//1
}
}