SpringBoot集成Redis
Redis基本命令:https://blog.csdn.net/HJW_233/article/details/131902164
参考文章:https://www.jianshu.com/p/cb6fb8f8bb83
1. 引入pom
org.springframework.boot spring-boot-starter-data-redis
2. 增加配置
spring: redis: host: 127.0.0.1 port: 6379 password: 123456
3. 自定义序列化
TODO: list 存储的对象还是存储的字节数组?
如果不自定义自定义序列化方式的话,查看缓存数据的时候是字节数组,看不懂!
OMS系统的配置
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.cache.CacheManager; 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.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; /** * redis配置 * * @author * @date 2021/12/7 3:07 下午 */ @Configuration @EnableCaching public class RedisConfig { /** * 长时过期时间(秒) */ private static final int REDIS_LONG_EXPIRATION = 86400 * 5; // 24小时 * 5 = 5天 /** * 定义长时的缓存器 * * @return */ @Bean(name = "longLifeCacheManager") public CacheManager longLifeCacheManager(RedisConnectionFactory factory) { RedisSerializer redisSerializer = new StringRedisSerializer(); // 配置序列化(解决乱码的问题),过期时间600秒 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(REDIS_LONG_EXPIRATION)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(this.getJacksonRedisSerializer())) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } /** * redisTemplate * * @param * @return org.springframework.data.redis.core.RedisTemplate * @author xiefengsong * @date 2020/4/26 9:57 上午 */ @Bean RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate template = new RedisTemplate(); //连接工厂 template.setConnectionFactory(redisConnectionFactory); //序列化 Jackson2JsonRedisSerializer serializer = this.getJacksonRedisSerializer(); template.setValueSerializer(serializer); //使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } /** * 配置序列化 * * @param * @return org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer * @author xiefengsong * @date 2020/4/26 9:43 上午 */ private Jackson2JsonRedisSerializer getJacksonRedisSerializer() { //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //采用的是自由放任所有的通行 mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper); return serializer; } }
参考文章的配置:
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.StringRedisSerializer; /** ** *
* * @author tianjiaxin * @createTime 2024/6/3 11:27 * @Description: */ @Configuration @EnableCaching public class RedisConfig { @Bean("redisTemplate") public RedisTemplate initRedisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); // 设置连接工厂 redisTemplate.setConnectionFactory(redisConnectionFactory); // 定义 String 序列化器 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 定义 Jackson 序列化器 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); //反序列化时智能识别变量名(识别没有按驼峰格式命名的变量名) objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //反序列化识别对象类型 objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY); //反序列化如果有多的属性,不抛出异常 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //反序列化如果碰到不识别的枚举值,是否作为空值解释,true:不会抛不识别的异常, 会赋空值,false:会抛不识别的异常 objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 设置 Redis 的 key 以及 hash 结构的 field 使用 String 序列化器 redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); // 设置 Redis 的 value 以及 hash 结构的 value 使用 Jackson 序列化器 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
4. 基本类型操作
package com.tjx.service.impl; import com.tjx.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SessionCallback; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.util.List; /** ** *
* * @author tianjiaxin * @createTime 2024/6/3 14:20 * @Description: */ @Service public class MyRedisServiceImpl { @Autowired RedisTemplate redisTemplate; @Autowired StringRedisTemplate stringRedisTemplate; // 基本操作 public void test1() { stringRedisTemplate.opsForValue().set("srt", "StringRedisTemplate"); redisTemplate.opsForValue().set("test1", new User(1L, "tjx", 18)); redisTemplate.opsForSet().add("set", "1", "2"); Boolean member = redisTemplate.opsForSet().isMember("set", "1"); System.out.println("==========" + member); redisTemplate.opsForList().leftPush("list", new User(2L, "小明", 19)); redisTemplate.opsForList().leftPush("list", new User(3L, "小红", 19)); redisTemplate.opsForList().rightPop("list"); } // 对一个key多次操作 public void test2() { BoundSetOperations bound = redisTemplate.boundSetOps("bound"); bound.add("1"); bound.add("2"); } // 事务 public void test3() { stringRedisTemplate.opsForValue().set("stock", "1000"); List results = stringRedisTemplate.execute(new SessionCallback() { @Override public List execute(RedisOperations redisOperations) throws DataAccessException { // 监控库存 redisOperations.watch((K) "stock"); // 获取库存 int stock = Integer.parseInt(String.valueOf(redisOperations.opsForValue().get("stock"))); // 如果库存在于购买数量,则库存构建,否则返回null if (stock > 10) { stock -= 10; } else { redisOperations.unwatch(); return null; } // 开启事务 redisOperations.multi(); // 扣减库存 redisOperations.opsForValue().set((K) "stock", (V) String.valueOf(stock)); // 执行事务 List exec = redisOperations.exec(); return exec; } }); if (results == null || results.size() == 0) { System.out.println("库存扣减失败!"); } else { System.out.println("剩余库存:" + stringRedisTemplate.opsForValue().get("stock")); } } // pipeline 多个命令批量发送都服务器上,减少网络传输 public void test4() { stringRedisTemplate.executePipelined(new SessionCallback() { @Override public Object execute(RedisOperations redisOperations) throws DataAccessException { stringRedisTemplate.opsForValue().set("pipeline1", "1"); stringRedisTemplate.opsForValue().set("pipeline2", "2"); stringRedisTemplate.opsForValue().set("pipeline3", "3"); return null; } }); } }
5. 搭配注解自动写入缓存
注意:在配置文件中添加@EnableCaching注解,其他配置还有依赖不需要添加
cacheNames:相当于key的前缀,含义是缓存存储的名称
- @CacheConfig,在类上使用,表示该类中方法使用的缓存名称(可以理解为数据缓存的命名空间),除了在类上使用该注解配置缓存名称,还可以用下边三个注解在方法上配置
- @CachePut,一般用在新增或更新业务的方法上,当数据新增或更新成功后,将方法的返回结果使用指定的 key 添加到缓存中,或更新缓存中已有的 key 的值
- @Cacheable,一般用在查询业务的方法上,先从缓存中根据指定的 key 查询数据,如果查询到就直接返回,否则执行该方法来获取数据,最后将方法的返回结果保存到缓存
- @CacheEvict,一般用在删除业务的方法上,默认会在方法执行结束后移除指定 key 对应的缓存数据
package com.tjx.service.impl; import com.tjx.dao.entity.StudentsDO; import com.tjx.dao.mapper.StudentsMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; /** *
* *
* * @author tianjiaxin * @createTime 2024/6/3 17:18 * @Description: */ @Service @CacheConfig(cacheNames = "studentSercieImpl") public class StudentServiceImpl { @Autowired StudentsMapper studentsMapper; @Cacheable(cacheNames = "getStudentsById", key = "'student' + #id") public StudentsDO getStudentsById(Integer id) { return studentsMapper.selectById(id); } @CachePut(key = "'student' + #studentsDO.id") public StudentsDO addStudents(StudentsDO studentsDO) { studentsMapper.insert(studentsDO); return studentsDO; } @CachePut(key = "'student' + #studentsDO.id", condition = "#result != 'null'") public StudentsDO updateStudents(StudentsDO studentsDO) { if (studentsDO == null) return null; studentsMapper.updateById(studentsDO); return studentsDO; } @CacheEvict(cacheNames = "delete", key = "'student' + #id") public Integer deleteUserById(Integer id) { return studentsMapper.deleteById(id); } }6. 基本操作工具类
package com.xiaomi.mit.oms.order.components.cache.manager; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.io.Serializable; import java.util.*; import java.util.concurrent.TimeUnit; @Slf4j @Component public class RedisManager { @Autowired private RedisTemplate redisTemplate; public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { log.error("[Redis] 设置key过期时间异常, key:{}, time:{}", key, time, e); return false; } } public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { log.warn("[Redis] 查询key值异常, key:{}", key, e); return false; } } public boolean delete(String key) { return redisTemplate.delete(key); } public void delete(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete(CollectionUtils.arrayToList(key)); } } } /** * 根据pattern删除 * * @param pattern */ public void deleteByPattern(String pattern) { Set keys = redisTemplate.keys(pattern); if (keys != null && keys.size() > 0) { redisTemplate.delete(keys); } } public List mGet(Collection keys) { return redisTemplate.opsForValue().multiGet(keys); } public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存获取 * * @param key 键 * @return 值 */ public String getString(String key) { return key == null ? null : (String) redisTemplate.opsForValue().get(key); } public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { log.error("[Redis] set设置key值异常, key:{}, value:{}", key, value, e); return false; } } public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { log.error("[Redis] set设置key值异常, key:{}, value:{}, time:{}", key, value, time, e); return false; } } public boolean setNx(String key, Object value, long time) { if (time 0) { expire(key, time); } return true; } catch (Exception e) { log.error("[Redis] Map设置异常, key:{}, map:{}, time:{}", key, map, time, e); return false; } } public boolean hmSet(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { log.error("[Redis] Map设置字段值异常, key:{}, item:{}, value:{}", key, item, value, e); return false; } } public boolean hmSet(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { log.error("[Redis] Map设置字段值异常, key:{}, item:{}, value:{}, time:{}", key, item, value, time, e); return false; } } public void hmDelete(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } public boolean hmHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } public double hmIncr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } public double hmDecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } // ============================set============================= public Set sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { log.error("[Redis] 根据key值获取Set异常, key:{}", key, e); return Collections.emptySet(); } } public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { log.error("[Redis] 根据key查询Set中是否存在value值异常, key:{}, value:{}", key, value, e); return false; } } public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { log.error("[Redis] 根据key查询Set中是否存在多个value值异常, key:{}, value:{}", key, values, e); return 0; } } public long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) { expire(key, time); } return count; } catch (Exception e) { log.error("[Redis] Set设置多个值并设置过期时间异常, key:{}, value:{}, time:{}", key, values, time, e); return 0; } } public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { log.error("[Redis] Set根据key值查询size异常, key:{}", key, e); return 0; } } public long setRemove(String key, Object... values) { try { return redisTemplate.opsForSet().remove(key, values); } catch (Exception e) { log.error("[Redis] Set根据key删除多个value异常, key:{}, value:{}", key, values, e); return 0L; } } public List lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { log.error("[Redis] List根据key查询对象异常, key:{}, start:{}, end:{}", key, start, end, e); return Collections.emptyList(); } } /** * 获取list缓存的内容,取出所有的值 * * @param key 键 * @return */ public List lGet(String key) { try { return redisTemplate.opsForList().range(key, 0, -1); } catch (Exception e) { log.error("[Redis] List根据key查询对象异常, key:{}, start:{}, end:{}", key, 0, -1, e); return Collections.emptyList(); } } public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { log.error("[Redis] List根据key查询对象size异常, key:{}", key, e); return 0; } } public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { log.error("[Redis] List根据key查询index对象异常, key:{}, index:{}", key, index, e); return null; } } public boolean rSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { log.error("[Redis] List right push对象异常, key:{}, value:{}", key, value, e); return false; } } public boolean rSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { log.error("[Redis] List right push对象异常, key:{}, value:{}, time:{}", key, value, time, e); return false; } } public boolean rSet(String key, List value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { log.error("[Redis] List right push list对象异常, key:{}, value:{}", key, value, e); return false; } } public boolean rSet(String key, List value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { log.error("[Redis] List right push list对象异常, key:{}, value:{}, time:{}", key, value, time, e); return false; } } public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { log.error("[Redis] List根据索引更新对象异常, key:{}, index:{}, value:{}", key, index, value, e); return false; } } public long lRemove(String key, long count, Object value) { try { return redisTemplate.opsForList().remove(key, count, value); } catch (Exception e) { log.error("[Redis] List 删除指定个数对象异常, key:{}, count:{}, value:{}", key, count, value, e); return 0; } } }
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。