一、介绍
- SpringBoot提供了Spring-data-redis的整合方法,整合了redisTemplate等调用方法和jedis连接池的实现,无须像SpringMVC进行繁琐的xml配置,配置全部在application.properties中完成。同时,Spring-Session-redis的整合也可以使用相同的配置项。
二、框架搭建
-
redis环境,自行搭建,参考
https://redis.io/
-
引入pom
<!-- spring redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
application.properties配置项中添加如下配置:
######################################################## ###Redis连接配置 ######################################################## ##Redis数据库索引(默认为0) spring.redis.database=2 spring.redis.host=127.0.0.1 spring.redis.port=6380 spring.redis.password=test2016 ## 连接池中的最大空闲连接 spring.redis.pool.max-idle=2000 ## 连接池中的最小空闲连接 spring.redis.pool.min-idle=1 ## 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=1000 ## 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=-1 ## 连接超时时间(毫秒) spring.redis.timeout=100000
三、 基础配置
-
创建配置类,@EnableCaching注解启用缓存;这里务必对key和value的序列化方式进行定义,否则存储redis时会处理乱码情况。
import org.springframework.cache.CacheManager; 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.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import com.fasterxml.jackson.databind.ObjectMapper; /** * @author xiaojin_wu * @email wuxiaojin258@126.com * @date 2018年3月13日 * @description redis缓存管理 */ @Configuration @EnableCaching//启用缓存 public class RedisConfig extends CachingConfigurerSupport{ /** springboot注入连接池 */ @Autowired private JedisConnectionFactory jedisConnectionFactory; @SuppressWarnings("rawtypes") @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); return rcm; } /** * RedisTemplate配置 * @param factory * @return */ @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new StringRedisTemplate(factory); //定义value的序列化方式 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // template.setKeySerializer(redisSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); //设置连接池 template.setConnectionFactory(jedisConnectionFactory); template.afterPropertiesSet(); return template; } }
四、基础封装
-
创建redis服务
import java.util.Set; import java.util.concurrent.TimeUnit; /** * @author * xiaojin_wu * @email * wuxiaojin258@126.com * @date * 2018年1月31日 * @description * redis服务 */ public interface IRedisService { /** * 根据指定key获取String * @param key * @return */ public String get(String key); /** * 设置Str缓存 * @param key * @param val */ public void set(String key, String val); /** * 设置Str缓存 * @param key * @param val * @param 有效时间,单位:秒 */ public void set(String key, String val,long validTime); /** * 设置Str缓存 * @param key * @param val * @param validTime * 有效时间,单位:秒 * @param unit * 缓存生效时间单位,java.util.concurrent.TimeUnit定义有静态时间单位常量 */ public void set(String key, String val,long validTime,TimeUnit unit); /** * 删除指定key * @param key */ public void del(String key); /** * 根据指定o获取Object * @param o * @return */ public Object getObject(Object o); /** * 设置obj缓存 * @param o1 * @param o2 */ public void setObject(Object o1, Object o2); /** * 删除Obj缓存 * @param o */ public void delObject(Object o); /** * 根据规则查询集合,通过keys命令查询 * @deprecated 线上环境性能差,废弃 * @param pattern */ @Deprecated public Set<String> getStringByPattern(String pattern); /** * 根据规则查询集合,通过keys命令查询 * @deprecated 线上环境性能差,废弃 * @param pattern */ @Deprecated public Set<Object> getObjectByPattern(String pattern); /** * 存储obj缓存并设置生效时间 * @param o1 * @param o2 */ public void setObject(Object key, Object val,long validTime,TimeUnit unit); /** * 操作列表进行rightpush * @param key * @param value */ public void rightPush(Object key,Object value); /** * 操作列表进行leftPush * @param key * @param value */ public void leftPush(Object key,Object value); /** * 操作列表进行leftPop * @param key */ public void leftPop(Object key); /** * 操作列表进行rightPop * @param key */ public void rightPop(Object key); /** * 操作列表,分页读取数据 * @param key * @param start * @param end * @return */ public List<?> range(Object key,long start,long end); /** * 操作列表,读取所有数据 * @param key * @return */ public List<?> rangeAll(Object key); /** * leftPushAll存储数组 */ public long leftPushAll(Object key,Object list); /** * rightPushAll存储数组 */ public long rightPushAll(Object key,Object list); /** * leftpush存储数组 * @param key * @param list */ public void pushAllToList(Object key,List<?> list,long validtime,TimeUnit unit); /** * 获取有效时间 * @param key * @return */ public long getValidTime(Object key,TimeUnit unit); /** * 使用redis的scan命令迭代进行模糊查询key集合,用于替换keys命令 * @param pattern * 模糊匹配的字符串 * @author xiaojin_wu * @return * 模糊匹配的key集合 */ public Set<String> getListByScan(String pattern); }
-
创建redis服务实现类,通过注解自动注入redisTemplate和StringRedisTemplate;此处封装了部分hash操作和list操作。
import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.TimeUnit; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import com.akucun.applets.common.redis.IRedisService; /** * @author xiaojin_wu * @email wuxiaojin258@126.com * @date 2018年1月31日 * @description redis公用方法实现类 */ // @Service(version = "1.0.0") @org.springframework.stereotype.Service public class RedisServiceImpl implements IRedisService { @Autowired StringRedisTemplate stringRedisTemplate; @Resource(name = "stringRedisTemplate") ValueOperations<String, String> valOpsStr; @Autowired RedisTemplate<Object, Object> redisTemplate; @Resource(name = "redisTemplate") ValueOperations<Object, Object> valOpsObj; /** * 根据指定key获取String * * @param key * @return */ public String get(String key) { return valOpsStr.get(key); } /** * 设置Str缓存 * * @param key * @param val */ public void set(String key, String val) { valOpsStr.set(key, val); } /** * 设置Str缓存 * * @param key * @param val * @param 有效时间,单位:秒 * @description void set(K key, V value, long offset); 这个api是设置从头开始 偏移多少位 void * set(K key, V value, long timeout, TimeUnit unit); 这个api才是过期时间 */ public void set(String key, String val, long validTime) { valOpsStr.set(key, val, validTime, TimeUnit.SECONDS); } /** * 设置Str缓存 * * @param key * @param val * @param validTime * 有效时间 * @param unit * 缓存生效时间单位,java.util.concurrent.TimeUnit定义有静态时间单位常量 */ public void set(String key, String val, long validTime, TimeUnit unit) { valOpsStr.set(key, val, validTime, unit); } /** * 删除指定key * * @param key */ public void del(String key) { stringRedisTemplate.delete(key); } /** * 根据指定o获取Object * * @param o * @return */ public Object getObject(Object o) { return valOpsObj.get(o); } /** * 设置obj缓存 * * @param o1 * @param o2 */ public void setObject(Object o1, Object o2) { valOpsObj.set(o1, o2); } /** * 删除Obj缓存 * * @param o */ public void delObject(Object o) { redisTemplate.delete(o); } @Override @Deprecated public Set<String> getStringByPattern(String pattern) { return stringRedisTemplate.keys("*" + pattern + "*"); } @Override public void setObject(Object key, Object val, long validTime, TimeUnit unit) { valOpsObj.set(key, val, validTime, unit); } @Override @Deprecated public Set<Object> getObjectByPattern(String pattern) { return redisTemplate.keys("*" + pattern + "*"); } @Override public void rightPush(Object key, Object value) { redisTemplate.opsForList().leftPush(key, value); } @Override public void leftPush(Object key, Object value) { redisTemplate.opsForList().leftPush(key, value); } @Override public void leftPop(Object key) { redisTemplate.opsForList().leftPop(key); } @Override public void rightPop(Object key) { redisTemplate.opsForList().rightPop(key); } @Override public List<?> range(Object key, long start, long end) { return redisTemplate.opsForList().range(key, start, end); } @Override public List<?> rangeAll(Object key) { return redisTemplate.opsForList().range(key, 0, -1); } @Override public long leftPushAll(Object key, Object list) { return redisTemplate.opsForList().leftPushAll(key, list); } @Override public long rightPushAll(Object key, Object list) { return redisTemplate.opsForList().rightPushAll(key, list); } @Override public void pushAllToList(Object key, List<?> list, long validtime, TimeUnit unit) { for (Object object : list) { leftPush(key, object); } redisTemplate.expire(key, validtime, unit); } @Override public long getValidTime(Object key, TimeUnit unit) { return redisTemplate.getExpire(key, unit); } @Override public Set<String> getListByScan(String pattern) { Set<String> set = new HashSet<>(); long count = 100;//初始化迭代增量 redisTemplate.execute(new RedisCallback<Iterable<byte[]>>() { @Override public Iterable<byte[]> doInRedis(RedisConnection connection) throws DataAccessException { ScanOptions options = ScanOptions.scanOptions().match(pattern+"*").count(count).build(); boolean done = false; // while循环确保能够获取到有效的cursor while (!done) { Cursor<byte[]> cursor = connection.scan(options); try { while (cursor.hasNext()) { String key = new String(cursor.next()); set.add(key); } done = true; // we've made it here, lets go away } catch (NoSuchElementException nse) { System.out.println("使用"+count+"条进行迭代增量不足,加倍进行迭代"); options = ScanOptions.scanOptions().match(pattern).count(count * 2).build(); } finally { connection.close(); } } return null; } }); return set; } }
五、使用注意
-
hash操作使用stringRedisTemplate
-
list、set等redis提供的数据结构操作使用redisTemplate
-
redis的key值命名推荐使用‘:’区分业务,在RedisDesktopManager远程连接redis的工具上会对redis存储的值进行分包分类,便于维护
-
对redis的key值进行模糊查询是,禁止使用keys命令,此处封装了scan的方式通过迭代进行模糊匹配
-
redis的scan命令会查询出重复记录,因此使用set存储查询结果集,参考:
http://www.redis.cn/commands/scan.html