文章目录
Redis是一个性能非常高的内存数据库,在项目中,通常会被用来做缓存中间件,除了可以用于存储数据外,也可以应用于消息发布/订阅的技术方案,还可以用于实现分布式锁。
本文主要从Redis的应用出发,介绍在java项目中,基于lettuce实现spring和redis的集成过程。
一、背景
1. java中对的redis使用
在java项目的源码开发中,对于redis的操作,通常是和spring框架进行集成,引入spring-data-redis客户端的jar包。
redis和spring的集成使用,论坛上有大量的技术贴可供参考。但博主发现,大部分技术贴在集成的使用上,并未说明集成的环境,不同的代码环境上,集成的方式还有使用的版本,是需要区分的。
2. spring-data-redis版本说明
这里说到了集成环境,就不得不说一下spring-data-redis客户端的发展史了。spring-data-redis是spring大家庭的一员,当前最新的版本,已经到了2.2.x了。spring-data-redis版本在1.8.x和2.0.x以后,是一个分水岭。
spring-data-redis1.8.x之前的版本中,默认使用Jedis作为客户端工具,spring-data-redis2.0.x之后,默认的的客户端工具变为io.lettuce.lettuce了。见spring-data-redis官方文档:
除了默认客户端的变化外,spring的版本也需要对应,官方的文档中,spring-data-redis2.0.x之后的版本,需要使用JDK8以上,spring5.x
二、集成方案
在说明了spring-data-redis的版本特性后,对于集成方案,需要区分来介绍。对于springboot项目,集成spring-data-redis是一件非常简单的事情,这里就不做过多的介绍了。博主主要是根据spring-data-redis1.8.x和spring-data-redis2.x两个有代表性的集成环境,分别对这两种集成方案进行说明:
在这里有必要说明一下spring-data-redis的客户端工具,spring-data-redis提供Jedis、Lettuce两种客户端工具,在多线程环境下,Jedis是一个非线程安全的,Lettuce底层是基于netty实现的,是线程安全的,在高并发环境下,Lettuce的性能和并发安全都能够得到保障。这也是spring-data-redis在2.x以上的版本中,默认使用Lettuce的主要原因。
虽然在spring-data-redis2.0之前的版本中,默认使用的是Jedis客户端,但也仍然支持Lettuce客户端,但这时的Lettuce使用的是biz.paluch.redis.lettuce。
在这两种集成方案中,我们都是用lettuce作为redis客户端。
本文重点是介绍方案一的集成方法(方案二可通过上述链接查看)。在集成中,不再使用xml配置方式,全部使用spring注解的方式,完成redis的集成。集成后支持redis单机、redis主从哨兵两种部署模式的redis的连接使用。
三、集成方法
1 引入依赖jar文件
在项目的pom.xml文件中,分别添加spring、spring-redis-data、lettuce等jar文件的依赖
1.1 引入spring 4.x相关jar文件
这里spring使用的是4.3.22.RELEASE版本,也可以使用spring4.x的其他小版本;
<!-- Spring 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
1.2 引入spring-data-redis相关的jar
spring-data相关的jar文件主要有3个,
<!-- redis集成 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
<version>1.2.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.13.18.RELEASE</version>
</dependency>
1.3 引入lettuce相关jar
lettuce需要使用到commons-pool2,因此引入的jar文件有
<!--spring-data 2.0之前的版本使用-->
<dependency>
<groupId>biz.paluch.redis</groupId>
<artifactId>lettuce</artifactId>
<version>4.2.2.Final</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.2</version>
</dependency>
2 创建redis配置
2.1 添加redis.properties
在src/main/resources目录下创建一个redis.properties,主要用于配置初始化及连接redis服务的参数,具体内容如下:
### redis模式(single-单机模式, sentinel-主从哨兵模式)
redis.deploy = single
### 连接池最大连接数(使用负值表示没有限制)
lettuce.pool.maxTotal=100
### 连接池中的最大空闲连接
lettuce.pool.maxIdle=100
### 连接池中的最小空闲连接
lettuce.pool.minIdle=50
### 单机模式地址
redis.host = 127.0.0.1
### 单机模式port
redis.port = 6379
### 单机模式密码
redis.password =
### 哨兵模式监听的master名称
lettuce.sentinel.master=mymaster
### 哨兵模式地址列表,多个以,分割
lettuce.sentinel.nodes=127.0.0.1:26301,127.0.0.1:26302,127.0.0.1:26303
2.2 创建properties初始化类
在工程中,创建一个类,用于读取redis.properties的配置文件(也可以基于spring的@Value注解实现配置文件属性的读取),
import java.util.ResourceBundle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import lombok.Data;
/**
* Copyright: Copyright (c) 2019 xxx有限公司
* @ClassName: RedisProperties.java
* @Description: Redis属性配置类
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月10日 上午9:23:40
*
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年10月10日 tblong v1.0.0 新建
*/
@Component
@Data
@Slf4j
public class RedisProperties {
private static ResourceBundle bundle;
static {
bundle = ResourceBundle.getBundle("redis");
log.debug("load redis.properties and init...");
}
/**
* 重新加载配置文件
*/
public void reloadProperties(){
bundle = ResourceBundle.getBundle("redis");
log.debug("reload redis.properties ...");
}
/**
* 获取String类型配置参数
* @param key
* @return
*/
public static String getString(String key) {
if(bundle.containsKey(key)){
return bundle.getString(key);
}
return null;
}
/**
* 获取Int类型配置参数
* @param key
* @return
*/
public static Integer getInt(String key) {
String value = getString(key);
if(value != null && !"".equals(value.trim())){
return Integer.parseInt(value.trim());
}
return null;
}
/**
* 获取Boolean类型配置参数
* @param key
* @return
*/
public static boolean getBoolean(String key) {
String value = getString(key);
if(value != null && !"".equals(value.trim())){
return Boolean.parseBoolean(value.trim());
}
return false;
}
}
2.3 创建redis属性bean
创建一个vo对象,用于将redis.properties属性中的参数封装成一个对象。代码如下:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.tian.tblong.prop.RedisProperties;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Data
@Slf4j
public class RedisInfoVo {
public RedisInfoVo(){
getConfigResource();
}
private String deployType;
private String host;
private int port;
private String password;
private int maxTotal;
private int maxIdle;
private int minIdle;
private String master;
private Set<String> hosts;
public void getConfigResource(){
loadBaseConfigInfo(); //加载基础参数配置
loadPropEvnConfigInfo(); //加载环境参数配置
}
/**
* 加载基础参数配置
*/
public void loadBaseConfigInfo(){
int maxTotal = RedisProperties.getInt("lettuce.pool.maxTotal");
int maxIdle = RedisProperties.getInt("lettuce.pool.maxIdle");
int minIdle = RedisProperties.getInt("lettuce.pool.minIdle");
this.maxTotal = maxTotal;
this.maxIdle = maxIdle;
this.minIdle = minIdle;
}
/**
* 加载环境参数配置
*/
public void loadPropEvnConfigInfo(){
String deploy = RedisProperties.getString("redis.deploy");
String host = RedisProperties.getString("redis.host");
int port = RedisProperties.getInt("redis.port");
String password = RedisProperties.getString("redis.password");
String master = RedisProperties.getString("lettuce.sentinel.master");
String sentinelNodes = RedisProperties.getString("lettuce.sentinel.nodes");
this.deployType = deploy;
this.host = host;
this.port = port;
this.password = password;
this.master = master;
if(sentinelNodes != null && !"".equals(sentinelNodes.trim())){
String[] sentinels = sentinelNodes.split(",");
hosts = new HashSet<>();
hosts.addAll(Arrays.asList(sentinels));
}
if("single".equals(deployType)){
log.info("load redis single conn info from properties : host->" + this.host + ", port->" + this.port + ", password->" + this.password);
}else if("sentinel".equals(deployType)){
log.info("load redis sentinel conn info from properties : master->" + this.master + ", hosts->" + sentinelNodes);
}
}
}
3 编写redis初始化配置类
创建RedisConfig.java类文件,编写redis的初始化核心配置代码:
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import com.tian.tblong.vo.RedisInfoVo;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
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.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Copyright: Copyright (c) 2019 xxx有限公司
* @ClassName: RedisConfig.java
* @Description: Redis换成初始化配置
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月10日 下午4:28:50
*
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年10月10日 tblong v1.0.0 新建
*/
@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfig extends CachingConfigurerSupport {
//redis参数配置信息
private RedisInfoVo redisVo = new RedisInfoVo();
@Override
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
//由于参数可能不同, 缓存的key也需要不一样
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* 缓存管理器
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//设置缓存过期时间
rcm.setUsePrefix(false);
rcm.setDefaultExpiration(600); //默认策略 ,10分钟
//配置不同缓存区域的过期时间,应用使用@Cacheable注解,设置value属性为以下指定的key,缓存的过期时间即为以下key值的过期时间
Map<String, Long> expires = new HashMap<String, Long>();
expires.put("business_data", 1800L); //指定key策略,30分钟
expires.put("system_data", 1800L); //指定key策略,30分钟
expires.put("common_data", 1800L); //指定key策略,30分钟
expires.put("test_data", 60L); //指定key策略,30分钟
rcm.setExpires(expires);
redisTemplate.getClientList();
return rcm;
}
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);// key序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* @Function: RedisConfig.java
* @Description: 连接工厂配置
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月10日 上午10:40:54
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年10月10日 tblong v1.0.0 新建
*/
@Bean
public LettuceConnectionFactory lettuceConnectionFactory(DefaultLettucePool defaultLettucePool) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(defaultLettucePool);
factory.setValidateConnection(true);
return factory;
}
/**
* @Function: RedisConfig.java
* @Description: 连接池配置
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月10日 下午3:19:17
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年10月10日 tblong v1.0.0 新建
*/
@Bean
public DefaultLettucePool getDefaultLettucePool(RedisSentinelConfiguration redisSentinelConfiguration, GenericObjectPoolConfig poolConfig) {
if("single".equalsIgnoreCase(redisVo.getDeployType())){
//redis单机模式配置
DefaultLettucePool defaultLettucePool = new DefaultLettucePool(redisVo.getHost(), redisVo.getPort(), poolConfig);
if(redisVo.getPassword() != null && !"".equals(redisVo.getPassword())){
defaultLettucePool.setPassword(redisVo.getPassword());
}
return defaultLettucePool;
}else if("sentinel".equalsIgnoreCase(redisVo.getDeployType())){
redis主从哨兵模式配置
DefaultLettucePool defaultLettucePool = new DefaultLettucePool(redisSentinelConfiguration);
defaultLettucePool.setPoolConfig(poolConfig);
defaultLettucePool.afterPropertiesSet();
return defaultLettucePool;
}else{
throw new RuntimeException("redis deploy type config error !!!, please check redis.properties.", new Throwable());
}
}
/**
* @Function: RedisConfig.java
* @Description: 配置哨兵集群信息 master和host:ip
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月10日 上午10:25:56
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年10月10日 tblong v1.0.0 新建
*/
@Bean
public RedisSentinelConfiguration redisSentinelConfiguration() {
return new RedisSentinelConfiguration(redisVo.getMaster(), redisVo.getHosts());
}
/**
* @Function: RedisConfig.java
* @Description: 线程池配置参数设置
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月10日 上午10:40:22
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年10月10日 tblong v1.0.0 新建
*/
@Bean
public GenericObjectPoolConfig genericObjectPoolConfig() {
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(redisVo.getMaxIdle());
poolConfig.setMinIdle(redisVo.getMinIdle());
poolConfig.setMaxTotal(redisVo.getMaxTotal());
//todo 其他配置
return poolConfig;
}
}
4 封装redis操作方法
在上面的步骤开发完成后,redis的集成就已经完成了。但要给业务类提供更好的redis方法使用,有必要对原生的RedisTemplate进行再次封装,提供更友好的方法给业务类使用。
创建一个RedisService方法,注入RedisTemplate,封装相关方法,代码如下:
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
/**
* Copyright: Copyright (c) 2019 xxx有限公司
* @ClassName: RedisService.java
* @Description: Redis服务入口类
* @version: v1.0.0
* @author: tblong
* @date: 2019年10月28日 上午11:12:29
*
* Modification History:
* Date Author Version Description
*-------------------------------------------------------------*
* 2019年10月28日 tblong v1.0.0 新建
*/
@Service
public class RedisService {
@Autowired
RedisTemplate<String, Object> redisTemplate;
// =============================common============================
/**
* 指定缓存失效时间
*
* @param key键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**
* 根据前缀删除key
* @param key
* @return
*/
public void delPrefix(String key) {
// TODO Auto-generated method stub
Set<String> keys = redisTemplate.keys(key);
redisTemplate.delete(keys);
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 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) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param by 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param by 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
/**
* 通过前缀获取储存在redis中的value
* @param prefix
* @return
*/
public Set<String> getByPrefix(String prefix) {
// TODO Auto-generated method stub
return redisTemplate.keys(prefix+"*");
}
// ================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(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) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key键
* @param item项
* @param by要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key键
* @param value值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key键
* @param values值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key键
* @param time时间(秒)
* @param values值 可以是多个
* @return 成功个数
*/
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) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key键
* @param values值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key键
* @param start开始
* @param end结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key键
* @param index索引
* index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key键
* @param value值
* @param time时间(秒)
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key键
* @param value值
* @param time时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key键
* @param value值
* @param time时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key键
* @param value值
* @param time时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key键
* @param index索引
* @param value值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key键
* @param count移除多少个
* @param value值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
5 验证
完成集成代码的开发后,使用一个单元测试方法,即可验证集成是否成功,简单的测试方法如下:
@Test
public void startRedis(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(InitConfiguretion.class);
RedisService redisService = (RedisService) applicationContext.getBean("redisService");
if(redisService != null){
redisService.set("ABC", "123456");
System.out.println("----->" + redisService.get("ABC"));
}
}
InitConfiguretion类的主要作用,是在类上面添加一个@ComponentScan(basePackages = “com”)自动扫描包的注解,让集成的代码初始化时加入到spring IOC容器中管理;
单元测试打印结果如下:
以上就是使用spring4.x和redis的集成全部过程!!!
本文对应的源码已上传github,需要的可下载查阅。源码下载
完