Redis使用之--基于Lettuce实现Spring和Redis的集成(一)

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,需要的可下载查阅。源码下载


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值