Spring集成Redis
最近在做一个关于群聊的项目,由于聊天要求实时性,不可能直接访问数据库,所以使用了Redis来做缓存,这里将使用过程中遇到的问题记录一下。
使用Redis之前需要合理设计存储在其中的数据结构,比如聊天系统,就需要存储包括用户登录状态信息,可以使用Hash数据结构,以用户Id做键,状态做值,还可以存储每个用户在每个群的未读消息计数,
客户端使用长轮询拉取。
最主要的就是群里的聊天记录的缓存了,这里可以使用Redis的List数据结构来做消息队列,其中按顺序存储消息实体对象(序列化后存入Redis)。还可以维护一个List存储聊天记录的主键便于定位聊天记录,等等的一系列数据都可以缓存到Redis。
Redis在Java中的实现是Jedis,其中封装了连接Redis的连接池实现、对Redis数据库的各种操作等。
在JavaWeb项目中使用Redis做缓存时有两种实现方式,第一种是使用原生的Jedis包,其中封装的方法可以直接操作Redis。第二种方法是使用Spring框架集成的Redis,其中封装Jedis对Redis的各种操作,包括事务、连接、连接池的维护等,其对Redis的操作进行了很多封装。
这个聊天项目一开始采用的是Spring封装的Redis,使用过程中发现,经常会报一些类型转换异常的问题,后来发现这种错误经常在网络连接异常或是长轮询的地方出现。深入底层发现是由于Redis底层的Socket连接使用了缓冲区,导致有些时候如果前面的连接出现问题,后面的请求再使用前面的连接会获取到前面连接的数据,导致类型转换异常的出现,
尤其是长轮询不断请求Redis服务器的时候,问题出现的频率尤其高,而且一旦出现问题,后面的连接都会出问题,这也许是由于Redis连接池中出问题的连接没有完全释放的原因。
因此建议大家如果使用Redis做缓存,最好使用原生的Jedis,这样可以在连接异常时自己实现异常连接的处理,而使用Spring集成的Redis由于连接已经被封装了,限制了自己对异常连接的处理。
下面就将两种集成Redis的方法分别介绍一下。
第一种是使用Spring集成的Redis。
1、首先是Jar包,需要jedis包、Spring集成Redis的包spring-data-redis、Redis连接池需要的commons-pool2包,其中spring-data-redis包和jedis包的版本需要适配,否则会报错,具体要求网上可以查到,这3个包的下载可以从Maven仓库获取。
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
<!-- spring-data-redis2.0.7版本下载失败 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.4.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2、Spring集成Redis的Xml配置
2.1、Redis.properties配置(相当于jdbc.properties)
#============================#
#==== Redis settings ====#
#============================#
#redis 服务器 IP
redis.host=192.168.1.222
#192.168.1.222
#格式:redis://:[密码]@[服务器地址]:[端口]/[db index]
redis.uri = redis://:12345@127.0.0.1:6379/0
#redis 服务器端口
redis.port=6379
#redis 密码
redis.pass=
#redis#2018
#超时时间
redis.timeOut=2000
#redis 支持16个数据库(相当于不同用户)可以使不同的应用程序数据彼此分开同时又存储在相同的实例上
redis.dbIndex=0
#redis 缓存数据过期时间单位秒
redis.expiration=3000
#连接池中最大连接数。高版本:maxTotal,低版本:maxActive
#控制一个 pool 可分配多少个jedis实例
redis.maxActive=6
#连接池中最少空闲的连接数
redis.minIdle=1
#连接池中最大空闲的连接数,控制一个 pool 最多有多少个状态为 idle 的jedis实例
redis.maxIdle=300
#当连接池资源耗尽时,调用者最大阻塞的时间,超时将抛出异常。单位,毫秒数;默认为-1.表示永不超时。高版本:maxWaitMillis,低版本:maxWait
#当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
redis.maxWait=1000
#连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除
redis.minEvictableIdleTimeMillis=60000
#对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3
redis.numTestsPerEvictionRun=3
#“空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1
redis.timeBetweenEvictionRunsMillis=30000
#testOnBorrow:向调用者输出“链接”资源时,是否检测是有有效,如果无效则从连接池中移除,并尝试获取继续获取。默认为false。建议保持默认值
#在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的;
redis.testOnBorrow=true
#testOnReturn:向连接池“归还”链接时,是否检测“链接”对象的有效性。默认为false。建议保持默认值
#testWhileIdle:向调用者输出“链接”对象时,是否检测它的空闲超时;默认为false。如果“链接”空闲超时,将会被移除。建议保持默认值
#whenExhaustedAction:当“连接池”中active数量达到阀值时,即“链接”资源耗尽时,连接池需要采取的手段, 默认为1(0:抛出异常。1:阻塞,直到有可用链接资源。2:强制创建新的链接资源)
2.2、applicationContext.xml引入redis.properties文件
<!-- 这里配置数据库properties文件位置 -->
<!-- 使用PropertyPlaceholderConfigurer加载redis.properties文件失败改用PropertySourcesPlaceholderConfigurer -->
<bean id="propertyConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:system.properties</value>
<value>classpath:redis.properties</value>
</list>
</property>
</bean>
将Redis相关配置单独放在一个配置文件中:
<import resource="spring-redis-context.xml" />
spring-redis-context.xml中的配置包括,连接池的配置、连接工厂的配置以及RedisTemplate类的相关配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<description>Spring容器管理redis连接和使用 </description>
<!--载入 redis 配置文件-->
<!-- Spring容器仅允许最多定义一个PropertyPlaceholderConfigurer 或 <content:property-placeholder>其余的会被Spring忽略 -->
<!-- <context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/> -->
<!-- 高版本Jedis没有maxActive变量,具体有哪些可以看JedisPoolConfig继承的类GenericObjectPoolConfig -->
<!-- 连接池配置 -->
<!-- 配置 JedisPoolConfig 实例 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxActive}"/>
<property name="maxWaitMillis" value="${redis.maxWait}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
</bean>
<!-- <bean id="clusterRedisNodes1" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg value="${redis.host}" />
<constructor-arg value="${redis.port}" type="int"/>
</bean> -->
<!-- ERR This instance has cluster support disabled -->
<!-- <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="maxRedirects" value="3"></property>
节点配置
<property name="clusterNodes">
<set>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="${redis.host}"/>
<constructor-arg name="port" value="${redis.port}"/>
</bean>
<bean class="org.springframework.data.redis.connection.RedisClusterNode">
<constructor-arg name="host" value="192.168.1.111"/>
<constructor-arg name="port" value="6380"/>
</bean>
</set>
</property>
</bean> -->
<!-- Spring提供的Redis连接工厂 -->
<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="password" value="${redis.pass}"/>
<property name="database" value="${redis.dbIndex}"/>
<property name="poolConfig" ref="poolConfig"/>
<!-- <constructor-arg ref="redisClusterConfiguration"></constructor-arg>
<constructor-arg ref="poolConfig"></constructor-arg> -->
<!-- <property name="clusterConfig" ref="redisClusterConfiguration"></property> -->
</bean>
<bean id="redisConfig" class="com.teriste.redis.util.RedisConfig"></bean>
<!-- Spring提供的访问Redis类 -->
<!-- 配置RedisTemplate -->
<!-- <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" scope="prototype">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
下面是设置key和value序列化的方式,不同方式导致存入的字节序列不一样,什么样的序列化方式就要使用相应的反序列化方式查询,否则差不多redis存入的数据
由此也可以知道spring对redis序列化有很多种方式
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
defaultSerializer是JdkSerializationRedisSerializer在调试时看不出来键是什么样的
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
fastjson序列化
<bean class="com.teriste.redis.util.FastJson2JsonRedisSerializer">
<constructor-arg name="clazz" value=Object.class></constructor-arg>
</bean>
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
配置true可以使用transactional控制事务,spring已经提供支持
<property name="enableTransactionSupport" value="true"/>
</bean> -->
<!-- 配置RedisCacheManager -->
<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg name="redisOperations" ref="redisTemplate"/>
<property name="defaultExpiration" value="${redis.expiration}"/>
</bean>
<!-- 配置RedisCacheConfig -->
<!-- <bean id="redisCacheConfig" class="com.teriste.redis.util.RedisCacheConfig">
<constructor-arg ref="jedisConnectionFactory"/>
<constructor-arg ref="redisTemplate"/>
<constructor-arg ref="redisCacheManager"/>
</bean> -->
<!-- Redis sentinel集群配置 -->
<!-- <bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<constructor-arg index="0" type="java.lang.String" value="host6379" />
<constructor-arg index="1" type="java.util.Set">
<set>
<value>192.168.1.111:6380</value>
<value>192.168.1.111:6381</value>
</set>
</constructor-arg>
</bean> -->
<!-- Spring提供的Redis连接工厂 -->
<!-- <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
Redis sentinel集群配置
<constructor-arg index="0" type="org.springframework.data.redis.connection.RedisSentinelConfiguration" ref="sentinelConfig" />
连接池配置.
<constructor-arg index="1" type="redis.clients.jedis.JedisPoolConfig" ref="poolConfig" />
Redis服务主机.
<property name="hostName" value="192.168.1.111" />
Redis服务端口号.
<property name="port" value="26379" />
Redis服务连接密码.
<property name="password" value="${redis.pass}" />
连超时设置.
<property name="timeout" value="15000" />
是否使用连接池.
<property name="usePool" value="true" />
</bean> -->
</beans>
RedisTemplate相关的配置在RedisConfig类中统一管理,再由容器注入,其中主要包括的是Java对象序列化存入Redis和从Redis反序列化到java对象的配置,因为Spring集成的redis默认是
JdkSerializationRedisSerializer,序列化后是字节数组,存入Redis不便于查看,所以需要自己配置键值的序列化方式,这里使用的是alibaba的fastjson2:
//RedisConfig.java
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.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.alibaba.fastjson.parser.ParserConfig;
@Configuration
public class RedisConfig
{
/**
* 重写Redis序列化方式,使用Json方式:
* 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。
* Spring Data JPA为我们提供了下面的Serializer:
* GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。
* 在此我们将自己配置RedisTemplate并定义Serializer。
* com.teriste.redis.util.FastJson2JsonRedisSerializer
* @param redisConnectionFactory
* @return
*/
@Bean(name="fastJson2JsonRedisSerializer")
@SuppressWarnings("rawtypes")
public RedisSerializer fastJson2JsonRedisSerializer(){
return new FastJson2JsonRedisSerializer<Object>(Object.class);
}
@Bean(name="redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
FastJson2JsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJson2JsonRedisSerializer<Object>(Object.class);
// 全局开启AutoType,不建议使用
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 建议使用这种方式,小范围指定白名单
ParserConfig.getGlobalInstance().addAccept("com.teriste.");
//设置键值序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(fastJsonRedisSerializer);
//设置hash键值序列化方式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
//FastJson2JsonRedisSerializer.java
import java.nio.charset.Charset;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
* 自定义序列化配置类
* @author Administrator
* @version 2018年5月24日
* @see FastJson2JsonRedisSerializer
* @since
*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t)
throws SerializationException
{
if (null==t)
{
return new byte[0];
}
return JSON.toJSONString(t,SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes)
throws SerializationException
{
if (null==bytes||bytes.length<=0)
{
return null;
}
String str=new String(bytes,DEFAULT_CHARSET);
return (T)JSON.parseObject(str, clazz);
}
}
还可以根据需要配置Redis键生成规则:
//RedisCacheConfig.java
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.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
/**
*
* spring-context since 4.1 才有CachingConfigurerSupport类
* @author Administrator
* @version 2018年5月21日
* @see RedisCacheConfig
* @since
*/
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
protected final static Logger log = LoggerFactory.getLogger(RedisCacheConfig.class);
private volatile JedisConnectionFactory mJedisConnectionFactory;
private volatile RedisTemplate<String, String> mRedisTemplate;
private volatile RedisCacheManager mRedisCacheManager;
public RedisCacheConfig() {
super();
}
public RedisCacheConfig(JedisConnectionFactory mJedisConnectionFactory, RedisTemplate<String, String> mRedisTemplate, RedisCacheManager mRedisCacheManager) {
super();
this.mJedisConnectionFactory = mJedisConnectionFactory;
this.mRedisTemplate = mRedisTemplate;
this.mRedisCacheManager = mRedisCacheManager;
}
public JedisConnectionFactory redisConnectionFactory() {
return mJedisConnectionFactory;
}
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
return mRedisTemplate;
}
public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
return mRedisCacheManager;
}
/**
* 该类告诉 spring 当前使用的缓存服务为 redis 并自定义了缓存 key 生成的规则。
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
下面就可以使用RedisTemplate类来操作Redis数据库了。
redisTemplate有两个方法经常用到,一个是opsForXXX一个是boundXXXOps,XXX是value的类型,前者获取到一个Opercation,但是没有指定操作的key,可以在一个连接(事务)内操作多个key以及对应的value;后者会获取到一个指定了key的operation,在一个连接内只操作这个key对应的value.
使用中发现一个问题,如果方法使用了Spring的@Transactional注解,那么在该方法里使用读取redis数据的方法获取不到数据,写入redis数据库的方法可以生效。
下面开始介绍第二种使用Redis的方式:原生Jedis。
1、同样还是需要redis.properties,以及在applicationContext.xml中引入redis.properties和单独的spring集成redis的配置文件。
2、配置jedis连接池
spring-redis-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<description>Spring容器管理redis连接和使用 </description>
<!--载入 redis 配置文件-->
<!-- Spring容器仅允许最多定义一个PropertyPlaceholderConfigurer 或 <content:property-placeholder>其余的会被Spring忽略 -->
<!-- <context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/> -->
<!-- 高版本Jedis没有maxActive变量,具体有哪些可以看JedisPoolConfig继承的类GenericObjectPoolConfig -->
<!-- 连接池配置 -->
<!--shardedJedisPool的相关配置-->
<!-- <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
新版是maxTotal,旧版是maxActive
<property name="maxTotal">
<value>${redis.maxActive}</value>
</property>
<property name="maxIdle">
<value>${redis.maxIdle}</value>
</property>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<property name="testOnReturn" value="true"/>
</bean>
<bean id="sharedJedisPool" class="redis.clients.jedis.ShardedJedisPool" scope="="singleton">
<constructor-arg index="0" ref="jedisPoolConfig"></constructor-arg>
<constructor-arg index="1">
<list>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg name="host" value="${redis.uri}"></constructor-arg>
</bean>
</list>
</constructor-arg>
</bean> -->
<!-- 高版本Jedis没有maxActive变量,具体有哪些可以看JedisPoolConfig继承的类GenericObjectPoolConfig -->
<!-- 连接池配置 -->
<!-- 配置 JedisPoolConfig 实例 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxActive}"/>
<property name="maxWaitMillis" value="${redis.maxWait}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="poolConfig" ref="jedisPoolConfig" />
<constructor-arg name="host" value="${redis.host}" />
<constructor-arg name="port" value="${redis.port}" type="int" />
<constructor-arg name="timeout" value="${redis.timeOut}" type="int" />
<!-- <constructor-arg name="password" value="${redis.pass}" />
<constructor-arg name="database" value="${redis.dbIndex}" type="int" /> -->
</bean>
<bean id="jedisClient" class="com.teriste.redis.util.JedisClient">
<constructor-arg name="jedisPool" ref="jedisPool"></constructor-arg>
<constructor-arg name="jedisPoolConfig" ref="jedisPoolConfig"></constructor-arg>
<constructor-arg name="host" value="${redis.host}" />
<constructor-arg name="port" value="${redis.port}" type="int" />
<constructor-arg name="timeout" value="${redis.timeOut}" type="int" />
</bean>
<bean id="redisClient" class="com.teriste.redis.util.RedisClient">
<constructor-arg name="jedisClient" ref="jedisClient"></constructor-arg>
</bean>
</beans>
其中的JedisClient.java类封装了连接和释放redis连接的方法,RedisClient类封装了对redis中各种数据类型的操作。
同样涉及到Java对象存入redis的问题,键是String类型的,所以直接使用String类的getBytes(charset)和new String(bytes, charset)来序列化和反序列化。值使用fastjson2。
StringSerializer.java实现键的序列化
import java.nio.charset.Charset;
/**
* 读写Hash数据结构数据的序列化与发序列化工具类
* @author Administrator
* @version 2018年7月9日
* @see StringSerializer
* @since
*/
public class StringSerializer
{
private static final Charset charset=Charset.forName("UTF-8");
/*public StringSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}*/
public static String deserialize(byte[] bytes) {
return bytes == null ? null : new String(bytes, charset);
}
public static byte[] serialize(String string) {
return string == null ? null : string.getBytes(charset);
}
}
FastJson2JsonSerializer.java实现值的序列化
import java.nio.charset.Charset;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class FastJson2JsonSerializer
{
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public static byte[] serialize(Object t)
throws SerializationException
{
if (null==t)
{
return new byte[0];
}
return JSON.toJSONString(t,SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@SuppressWarnings(value={"unchecked","rawtypes"})
public static Object deserialize(byte[] bytes, Class clazz)
throws SerializationException
{
if (null==bytes||bytes.length<=0)
{
return null;
}
String str=new String(bytes,DEFAULT_CHARSET);
return JSON.parseObject(str, clazz);
}
}
下面是对redis连接的封装:JedisClient.java
import org.apache.log4j.Logger;
import com.teriste.core.utils.SpringContextHolder;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.exceptions.JedisException;
public class JedisClient
{
/**
* 日志
*/
private static Logger logger = Logger.getLogger(JedisClient.class);
private JedisPool jedisPool;//注入JedisPool
private JedisPoolConfig jedisPoolConfig;
private String host;
private int port;
private int timeout;
public JedisClient(JedisPool jedisPool,JedisPoolConfig jedisPoolConfig,String host, int port,int timeout){
this.jedisPool=jedisPool;
this.jedisPoolConfig=jedisPoolConfig;
this.host=host;
this.port=port;
this.timeout=timeout;
}
//获取Redis资源
public synchronized Jedis getJedis(){
try
{
if (jedisPool==null)
{
jedisPool=(JedisPool)SpringContextHolder.getApplicationContext().getBean("jedisPool");
}
Jedis jedis=jedisPool.getResource();
return jedis;
}
catch (Exception e)
{
e.printStackTrace();
//获取Redis连接时如果发生异常就重置连接池
if (null!=jedisPool)
{
jedisPool.destroy();
jedisPool=new JedisPool(jedisPoolConfig,host,port,timeout);
}
System.out.println(jedisPool.isClosed()+"----------------");
if (jedisPool!=null)
{
Jedis jedis=jedisPool.getResource();
return jedis;
}
}
return null;
}
//释放redis资源
public synchronized void releaseConn(Jedis jedis,Exception exception){
/*if (null!=exception)
{
if (exception instanceof JedisConnectionException) {
logger.error("Redis connection " + jedisPool.getResource().getClient().getHost() + " lost.", exception);
} else if (exception instanceof JedisDataException) {
if ((exception.getMessage() != null) && (exception.getMessage().indexOf("READONLY") != -1)) {
logger.error("Redis connection " + jedisPool.getResource().getClient().getHost() + " are read-only slave.", exception);
} else {
// dataException, isBroken=false
}
} else {
logger.error("Jedis exception happen.", exception);
}
}*/
try
{
if (null!=jedis)
{
//Jedis的close()会先判断连接是否损毁如果是就走释放损毁连接的方法,否则走正常连接的方法。
jedis.close();
}
}
catch (Exception e)
{
logger.error("return back jedis failed, will fore close the jedis.", e);
//如果close()方法执行失败就直接将jedis引用置空
jedis=null;
}
/*try
{
if (jedis!=null)
{
jedisPool.returnResource(jedis);
}
}
catch (Exception e)
{
if (jedis!=null)
{
try
{
jedisPool.returnBrokenResource(jedis);
}
catch (Exception e2)
{
jedis=null;
}
}
}*/
}
/**
* Handle jedisException, write log and return whether the connection is broken.
*/
protected boolean handleJedisException(JedisException jedisException) {
if (jedisException instanceof JedisConnectionException) {
logger.error("Redis connection " + jedisPool.getResource().getClient().getHost() + " lost.", jedisException);
} else if (jedisException instanceof JedisDataException) {
if ((jedisException.getMessage() != null) && (jedisException.getMessage().indexOf("READONLY") != -1)) {
logger.error("Redis connection " + jedisPool.getResource().getClient().getHost() + " are read-only slave.", jedisException);
} else {
// dataException, isBroken=false
return false;
}
} else {
logger.error("Jedis exception happen.", jedisException);
}
return true;
}
/**
* Return jedis connection to the pool, call different return methods depends on the conectionBroken status.
*/
@SuppressWarnings("deprecation")
protected void closeResource(Jedis jedis, boolean conectionBroken) {
try {
if (conectionBroken) {
jedisPool.returnBrokenResource(jedis);
} else {
jedisPool.returnResource(jedis);
}
} catch (Exception e) {
logger.error("return back jedis failed, will fore close the jedis.", e);
jedis=null;
}
}
public JedisPool getJedisPool()
{
return jedisPool;
}
public void setJedisPool(JedisPool jedisPool)
{
this.jedisPool = jedisPool;
}
public JedisPoolConfig getJedisPoolConfig()
{
return jedisPoolConfig;
}
public void setJedisPoolConfig(JedisPoolConfig jedisPoolConfig)
{
this.jedisPoolConfig = jedisPoolConfig;
}
public String getHost()
{
return host;
}
public void setHost(String host)
{
this.host = host;
}
public int getPort()
{
return port;
}
public void setPort(int port)
{
this.port = port;
}
public int getTimeout()
{
return timeout;
}
public void setTimeout(int timeout)
{
this.timeout = timeout;
}
public static Logger getLogger()
{
return logger;
}
public static void setLogger(Logger logger)
{
JedisClient.logger = logger;
}
}
下面是对部分操作Redis数据的封装:RedisClient.java
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
import org.springframework.data.redis.connection.jedis.JedisConverters;
import org.springframework.data.redis.core.TimeoutUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.Assert;
import redis.clients.jedis.Jedis;
public class RedisClient
{
private JedisClient jedisClient;
public RedisClient(JedisClient jedisClient){
this.jedisClient=jedisClient;
}
//键序列化与反序列化:StringSerializer
//值序列化与反序列化:FastJson2JsonSerializer
/**
* 数据结构之外的处理
*/
/**
* 删除Redis中指定的键
* @param key
* @see
*/
public void del(String key) {
final byte[] rawKey = rawString(key);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
jedis.del(new byte[][] { rawKey });
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* 删除Redis中多个键
* @param keys
* @see
*/
public void del(Collection<String> keys) {
if (CollectionUtils.isEmpty(keys)) {
return;
}
final byte[][] rawKeys = rawKeys(keys);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
jedis.del(rawKeys);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* 判断Redis中键是否存在
* @param key
* @return
* @see
*/
public Boolean exists(String key){
final byte[] rawKey = rawString(key);
Jedis jedis=null;
Boolean exists=null;
try
{
jedis=jedisClient.getJedis();
exists=jedis.exists(rawKey);
return exists;
}
catch (Exception e)
{
e.printStackTrace();
return false;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
private byte[][] rawKeys(Collection<String> keys) {
byte[][] rawKeys = new byte[keys.size()][];
int i = 0;
for (String key : keys) {
rawKeys[(i++)] = rawString(key);
}
return rawKeys;
}
/**
* ################Hash##################
*/
/**
* Hash数据结构判断值的键是否存在
* @param key
* @param hashKey
* @return
* @see
*/
public Boolean hExists(String key, String hashKey) {
final byte[] rawKey = rawString(key);
final byte[] rawHashKey = rawHashKey(hashKey);
Jedis jedis=null;
Boolean exists=null;
try
{
jedis=jedisClient.getJedis();
exists=jedis.hexists(rawKey, rawHashKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return exists;
}
/**
* Hash数据结构删除值键
* @param key
* @param hashKeys
* @return
* @see
*/
public Long hDel(String key,Object... hashKeys){
final byte[] rawKey = rawString(key);
final byte[][] rawHashKeys = rawHashKeys(hashKeys);
Jedis jedis=null;
Long delNum=null;
try
{
jedis=jedisClient.getJedis();
delNum=jedis.hdel(rawKey, rawHashKeys);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return delNum;
}
/**
* Hash数据结构获取键对应的值键的集合
* @param key
* @return
* @see
*/
public Set<String> hKeys(String key){
final byte[] rawKey = rawString(key);
Jedis jedis=null;
Set<byte[]> rawValues=null;
try
{
jedis=jedisClient.getJedis();
rawValues=jedis.hkeys(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return deserializeHashKeys(rawValues);
}
/**
* Hash数据结构获取值键对应的值的集合
* @param key
* @param clazz
* @return
* @see
*/
public List<Object> values(String key,Class clazz){
final byte[] rawKey = rawString(key);
Jedis jedis=null;
List<byte[]> rawValues=null;
try
{
jedis=jedisClient.getJedis();
rawValues=jedis.hvals(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return deserializeHashValues(rawValues,clazz);
}
/**
* Hash数据结构获取键对应的值键的个数
* @param key
* @return
* @see
*/
public Long hLen(String key) {
final byte[] rawKey = rawString(key);
Jedis jedis=null;
Long len=null;
try
{
jedis=jedisClient.getJedis();
len=jedis.hlen(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return len;
}
/**
* 获取hash数据结果的值
* @param key
* @param hashKey
* @param clazz
* @return
* @see
*/
public Object hGet(String key,String hashKey,Class clazz){
final byte[] rawKey=rawString(key);
final byte[] rawHashKey=rawHashKey(hashKey);
byte[] rawHashValue =null;
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
rawHashValue=jedis.hget(rawKey,rawHashKey);
}
catch (Exception e)
{
e.printStackTrace();
}
finally{
jedisClient.releaseConn(jedis,null);
}
return FastJson2JsonSerializer.deserialize(rawHashValue,clazz);
}
/**
* Hash数据结构获取多个键的值列表
* @param key
* @param fields
* @param clazz
* @return
* @see
*/
public List<Object> hMGet(String key,List<String> fields,Class clazz){
if (fields.isEmpty()) {
return Collections.emptyList();
}
final byte[] rawKey = rawString(key);
final byte[][] rawHashKeys = new byte[fields.size()][];
int counter = 0;
for (String hashKey : fields) {
rawHashKeys[(counter++)] = rawHashKey(hashKey);
}
Jedis jedis=null;
List<byte[]> rawValues=null;
try
{
jedis=jedisClient.getJedis();
rawValues=jedis.hmget(rawKey, rawHashKeys);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return deserializeHashValues(rawValues,clazz);
}
/**
* 根据键获取hash数据结构所有数据
* @param key
* @param hashKey
* @param clazz:值的类型
* @return
* @see
*/
public Map<Object, Object> hGetAll(String key,Class clazz){
final byte[] rawKey=rawString(key);
Map<byte[], byte[]> rawHashValue =null;
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
rawHashValue=jedis.hgetAll(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return deserializeHashMap(rawHashValue,clazz);
}
/**
* 保存或更新hash数据
* @param key
* @param hashKey
* @param value
* @return
* @see
*/
public Boolean hSet(String key,String hashKey,Object value){
final byte[] rawKey = rawString(key);
final byte[] rawHashKey = rawHashKey(hashKey);
final byte[] rawHashValue = rawValue(value);
Jedis jedis=jedisClient.getJedis();
try
{
Boolean result=JedisConverters.toBoolean(jedis.hset(rawKey, rawHashKey, rawHashValue));
jedisClient.releaseConn(jedis,null);
return result;
}
catch (Exception e)
{
jedisClient.releaseConn(jedis,e);
return false;
}
}
/**
* hash数据结构保存多个键值对
* @param key
* @param m
* @return
* @see
*/
public Boolean hMSet(String key,Map<String, Object> m){
if (m.isEmpty()) {
return false;
}
final byte[] rawKey = rawString(key);
final Map<byte[], byte[]> hashes = new LinkedHashMap<byte[], byte[]>(m.size());
for (Map.Entry<String, Object> entry : m.entrySet()) {
hashes.put(rawHashKey(entry.getKey()), rawValue(entry.getValue()));
}
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
jedis.hmset(rawKey, hashes);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return true;
}
//key序列化
public byte[] rawString(String key){
return StringSerializer.serialize(key);
}
//hashkey序列化
public byte[] rawHashKey(Object hashKey){
return StringSerializer.serialize(hashKey.toString());
}
//多个值键序列化
public byte[][] rawHashKeys(Object... hashKeys) {
byte[][] rawHashKeys = new byte[hashKeys.length][];
int i = 0;
for (Object hashKey : hashKeys) {
rawHashKeys[(i++)] = rawHashKey(hashKey);
}
return rawHashKeys;
}
//值序列化
public byte[] rawValue(Object value){
return FastJson2JsonSerializer.serialize(value);
}
//hash键反序列化
public Set<String> deserializeHashKeys(Set<byte[]> rawKeys){
if (rawKeys == null) {
return null;
}
Set<String> values =new LinkedHashSet<String>(rawKeys.size());
for (byte[] bs : rawKeys) {
values.add(StringSerializer.deserialize(bs));
}
return values;
}
//hash结构值是String类型的反序列化
public List<Object> deserializeHashValues(List<byte[]> rawValues,Class clazz){
if (rawValues == null) {
return null;
}
List<Object> values =new ArrayList<Object>();
for (byte[] bs : rawValues) {
values.add(FastJson2JsonSerializer.deserialize(bs,clazz));
}
return values;
}
/**
* ################List##################
*/
/**
* List数据结构获取指定索引位置的值
* @param key
* @param index
* @param clazz
* @return
* @see
*/
public Object lIndex(String key, final long index,Class clazz) {
final byte[] rawKey = rawString(key);
Jedis jedis=null;
byte[] value=null;
try
{
jedis=jedisClient.getJedis();
value=jedis.lindex(rawKey, index);
return deserializeValue(value,clazz);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构获取键对应的值集合大小
* @param key
* @return
* @see
*/
public Long lLen(String key)
{
final byte[] rawKey = rawString(key);
Jedis jedis=null;
Long len=null;
try
{
jedis=jedisClient.getJedis();
len=jedis.llen(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return len;
}
/**
* List数据结构获取指定范围的值集合
* @param key
* @param start
* @param end
* @param clazz
* @return
* @see
*/
public List<Object> lRange(String key, final long start, long end,Class clazz)
{
final byte[] rawKey = rawString(key);
Jedis jedis=null;
List<byte[]> rawValues=null;
try
{
jedis=jedisClient.getJedis();
rawValues=jedis.lrange(rawKey, start, end);
return deserializeValues(rawValues,clazz);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构移除指定值
* @param key
* @param count
* @param value
* @return
* @see
*/
public Long lRem(String key, final long count, Object value)
{
final byte[] rawKey = rawString(key);
byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long remNum=null;
try
{
jedis=jedisClient.getJedis();
remNum=jedis.lrem(rawKey, count, rawValue);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return remNum;
}
/**
* List数据结构从左侧弹出值对象
* @param key
* @param clazz
* @return
* @see
*/
public Object lLPop(String key,Class clazz){
final byte[] rawKey = rawString(key);
Jedis jedis=null;
byte[] value=null;
try
{
jedis=jedisClient.getJedis();
value=jedis.lpop(rawKey);
return deserializeValue(value,clazz);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构从左侧弹出值的字节数组
* @param key
* @param timeout
* @param unit
* @return
* @see
*/
public byte[] lLPop(String key, long timeout, TimeUnit unit)
{
final int tm = (int)TimeoutUtils.toSeconds(timeout, unit);
final byte[] rawKey = rawString(key);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
List<byte[]> bLPop=jedis.blpop(tm, new byte[][] { rawKey });
return CollectionUtils.isEmpty(bLPop) ? null : (byte[])bLPop.get(1);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构从左侧插入数据
* @param key
* @param value
* @return
* @see
*/
public Long lLeftPush(String key, Object value)
{
final byte[] rawKey = rawString(key);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.lpush(rawKey, new byte[][] { rawValue });
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构左侧插入值数组
* @param key
* @param values
* @return
* @see
*/
public Long lLeftPushAll(String key, Object[] values)
{
final byte[] rawKey = rawString(key);
final byte[][] rawValues = rawValues(values);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.lpush(rawKey, rawValues);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构左侧插入值集合
* @param key
* @param values
* @return
* @see
*/
public Long lLeftPushAll(String key, Collection<Object> values)
{
final byte[] rawKey = rawString(key);
final byte[][] rawValues = rawValues(values);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.lpush(rawKey, rawValues);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构如果值存在从左侧插入
* @param key
* @param value
* @return
* @see
*/
public Long lLeftPushIfPresent(String key, Object value)
{
final byte[] rawKey = rawString(key);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.lpushx(rawKey, rawValue);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构按优先级从左侧插入
* @param key
* @param pivot
* @param value
* @return
* @see
*/
public Long lLeftPush(String key, Object pivot, Object value)
{
final byte[] rawKey = rawString(key);
final byte[] rawPivot = rawValue(pivot);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.linsert(rawKey, LIST_POSITION.BEFORE, rawPivot, rawValue);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构从右侧弹出值对象
* @param key
* @param clazz
* @return
* @see
*/
public Object lRPop(String key,Class clazz){
final byte[] rawKey = rawString(key);
Jedis jedis=null;
byte[] value=null;
try
{
jedis=jedisClient.getJedis();
value=jedis.rpop(rawKey);
return deserializeValue(value,clazz);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构从右侧弹出值的字节数组
* @param key
* @param timeout
* @param unit
* @return
* @see
*/
public byte[] lRPop(String key, long timeout, TimeUnit unit)
{
final int tm = (int)TimeoutUtils.toSeconds(timeout, unit);
final byte[] rawKey = rawString(key);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
List<byte[]> bRPop=jedis.brpop(tm, new byte[][] { rawKey });
return CollectionUtils.isEmpty(bRPop) ? null : (byte[])bRPop.get(1);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构右侧插入值
* @param key
* @param values
* @return
* @see
*/
public Long lRightPush(String key, Object value)
{
final byte[] rawKey = rawString(key);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.rpush(rawKey, new byte[][] { rawValue });
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构右侧插入值数组
* @param key
* @param values
* @return
* @see
*/
public Long lRightPushAll(String key, Object[] values)
{
final byte[] rawKey = rawString(key);
final byte[][] rawValues = rawValues(values);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.rpush(rawKey, rawValues);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构右侧插入值集合
* @param key
* @param values
* @return
* @see
*/
public Long lRightPushAll(String key, Collection<Object> values)
{
final byte[] rawKey = rawString(key);
final byte[][] rawValues = rawValues(values);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.rpush(rawKey, rawValues);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构如果值存在从右侧插入
* @param key
* @param value
* @return
* @see
*/
public Long lRightPushIfPresent(String key, Object value)
{
final byte[] rawKey = rawString(key);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.rpushx(rawKey, rawValue);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构按优先级从右侧插入
* @param key
* @param pivot
* @param value
* @return
* @see
*/
public Long lRightPush(String key, Object pivot, Object value)
{
final byte[] rawKey = rawString(key);
final byte[] rawPivot = rawValue(pivot);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
Long pushNum=null;
try
{
jedis=jedisClient.getJedis();
pushNum=jedis.linsert(rawKey, LIST_POSITION.AFTER, rawPivot, rawValue);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return pushNum;
}
/**
* List数据结构从一个列表的右侧弹出值从另一个列表的左侧插入
* @param sourceKey
* @param destinationKey
* @return
* @see
*/
public byte[] rightPopAndLeftPush(String sourceKey, String destinationKey){
final byte[] rawSourceKey = rawString(sourceKey);
final byte[] rawDestKey = rawString(destinationKey);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
return jedis.rpoplpush(rawSourceKey, rawDestKey);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构从一个列表的右侧弹出值从另一个列表的左侧插入
* @param sourceKey
* @param destinationKey
* @param timeout
* @param unit
* @return
* @see
*/
public byte[] rightPopAndLeftPush(String sourceKey, String destinationKey, long timeout, TimeUnit unit){
final int tm = (int)TimeoutUtils.toSeconds(timeout, unit);
final byte[] rawSourceKey = rawString(sourceKey);
final byte[] rawDestKey = rawString(destinationKey);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
return jedis.brpoplpush(rawSourceKey, rawDestKey,tm);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构替换掉在键的指定索引处的值
* @param key
* @param index
* @param value
* @see
*/
public void set(String key, final long index, Object value){
final byte[] rawKey = rawString(key);
final byte[] rawValue = rawValue(value);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
jedis.lset(rawKey, index, rawValue);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构按索引位置截取指定键的列表
* @param key
* @param start
* @param end
* @see
*/
public void trim(String key, final long start, long end){
final byte[] rawKey = rawString(key);
Jedis jedis=null;
try
{
jedis=jedisClient.getJedis();
jedis.ltrim(rawKey, start, end);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* List数据结构序列化值
* @param values
* @return
* @see
*/
public byte[][] rawValues(Collection<Object> values)
{
Assert.notEmpty(values, "Values must not be 'null' or empty.");
Assert.noNullElements(values.toArray(), "Values must not contain 'null' value.");
byte[][] rawValues = new byte[values.size()][];
int i = 0;
for (Iterator<Object> localIterator = values.iterator(); localIterator.hasNext(); ) {
Object value = localIterator.next();
rawValues[(i++)] = rawValue(value);
}
return rawValues;
}
/**
* List数据结构值反序列化
* @param value
* @param clazz
* @return
* @see
*/
public Object deserializeValue(byte[] value,Class clazz)
{
if (value == null) {
return null;
}
return FastJson2JsonSerializer.deserialize(value,clazz);
}
/**
* List数据结构值集合反序列化
* @param rawValues
* @param clazz
* @return
* @see
*/
public List<Object> deserializeValues(List<byte[]> rawValues,Class clazz){
if (rawValues == null) {
return null;
}
List<Object> values =new ArrayList<Object>();
for (byte[] bs : rawValues) {
values.add(FastJson2JsonSerializer.deserialize(bs,clazz));
}
return values;
}
/**
* ################Set##################
*/
/**
* Set数据结构中是否存在某个值
* @param key
* @param o
* @return
* @see
*/
public Boolean sIsMember(String key, Object o)
{
final byte[] rawKey = rawString(key);
final byte[] rawValue = rawValue(o);
Jedis jedis=null;
Boolean isMember=null;
try
{
jedis=jedisClient.getJedis();
isMember=jedis.sismember(rawKey, rawValue);
return isMember;
}
catch (Exception e)
{
e.printStackTrace();
return false;
}finally{
jedisClient.releaseConn(jedis,null);
}
}
/**
* Set数据结构中值的集合
* @param key
* @param clazz
* @return
* @see
*/
public Set<Object> sMembers(String key,Class clazz)
{
final byte[] rawKey = rawString(key);
Jedis jedis=null;
Set<byte[]> rawValues=null;
try
{
jedis=jedisClient.getJedis();
rawValues=jedis.smembers(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return deserializeValues(rawValues,clazz);
}
/**
* Set数据结构移除指定值
* @param key
* @param values
* @return
* @see
*/
public Long sRem(String key, Object[] values) {
final byte[] rawKey = rawString(key);
final byte[][] rawValues = rawValues(values);
Jedis jedis=null;
Long remNum=null;
try
{
jedis=jedisClient.getJedis();
remNum=jedis.srem(rawKey, rawValues);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return remNum;
}
/**
* Set数据结构获取键包含的值集合大小
* @param key
* @return
* @see
*/
public Long sCard(String key) {
final byte[] rawKey = rawString(key);
Jedis jedis=null;
Long size=null;
try
{
jedis=jedisClient.getJedis();
size=jedis.scard(rawKey);
}
catch (Exception e)
{
e.printStackTrace();
}finally{
jedisClient.releaseConn(jedis,null);
}
return size;
}
/**
* Set数据结构反序列化值集合
* @param rawValues
* @param clazz
* @return
* @see
*/
public Set<Object> deserializeValues(Set<byte[]> rawValues,Class clazz){
if (rawValues == null) {
return null;
}
Set<Object> values =new LinkedHashSet<Object>(rawValues.size());
for (byte[] bs : rawValues) {
values.add(FastJson2JsonSerializer.deserialize(bs,clazz));
}
return values;
}
//Set值序列化
public byte[][] rawValues(Object[] values){
if (null==values)
{
return null;
}
byte[][] rawValues = new byte[values.length][];
int i = 0;
for (Object value : values) {
rawValues[(i++)] = rawValue(value);
}
return rawValues;
}
//序列化Map数据结构
public Map<Object, Object> deserializeHashMap(Map<byte[], byte[]> entries,Class clazz){
if (entries == null) {
return null;
}
Map<Object, Object> map = new LinkedHashMap<Object, Object>(entries.size());
for (Map.Entry<byte[], byte[]> entry : entries.entrySet()) {
map.put(StringSerializer.deserialize((byte[])entry.getKey()), FastJson2JsonSerializer.deserialize((byte[])entry.getValue(), clazz));
}
return map;
}
public JedisClient getJedisClient()
{
return jedisClient;
}
public void setJedisClient(JedisClient jedisClient)
{
this.jedisClient = jedisClient;
}
}
还没有评论,来说两句吧...