背景:
当redis里面需要存储 “key-字符串,value-对象” 时,是不能直接存对象,而是需要将序列化后或转换为JSON后的对象存进redis。
redis没有实现内部序列化对象的功能,所以需要自己提前序列化对象及转换为Json对象。
序列化介绍:
序列化的方法有很多,比如java原生序列化(需要实现Serializable接口)、json序列化、protobuff序列化。
protobuff序列化:告诉我对象的class,内部有schema来描述你的class是什么结构,class必须有get/set方法这种标准的类,而不是string等类。
第一种:将数据对象转换为JSONString存入redis
1.首先pom文件导入
-
<!-- Jedis connection redis-->
-
<dependency>
-
<groupId>org.apache.commons</groupId>
-
<artifactId>commons-pool2</artifactId>
-
<version>2.4.2</version>
-
</dependency>
-
<dependency>
-
<groupId>redis.clients</groupId>
-
<artifactId>jedis</artifactId>
-
<version>2.9.0</version>
-
<type>jar</type>
-
<scope>compile</scope>
-
</dependency>
-
<!-- protostuff序列化依赖 -->
-
<dependency>
-
<groupId>com.dyuproject.protostuff</groupId>
-
<artifactId>protostuff-core</artifactId>
-
<version>1.0.8</version>
-
</dependency>
-
<dependency>
-
<groupId>com.dyuproject.protostuff</groupId>
-
<artifactId>protostuff-runtime</artifactId>
-
<version>1.0.8</version>
- </dependency>
2.redis.properties文件配置及 spring文件配置
-
redis.pool.maxTotal=1000
-
redis.pool.maxIdle=200
-
redis.pool.maxWaitMillis=2000
-
redis.pool.testOnBorrow=true
-
jedis.host=127.0.0.1
-
jedis.port=6379
-
<context:property-placeholder location="classpath:redis.properties" file-encoding="utf-8" ignore-unresolvable="true"></context:property-placeholder>
-
<!-- Jedis config-->
-
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
-
<property name="maxTotal" value="${redis.pool.maxTotal}"/>
-
<property name="maxIdle" value="${redis.pool.maxIdle}"/>
-
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"/>
-
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
-
</bean>
-
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
-
<constructor-arg ref="jedisPoolConfig"/>
-
<constructor-arg value="${jedis.host}" type="java.lang.String"/>
-
<constructor-arg type="int" value="${jedis.port}"/>
-
</bean>
3.写一个RedisUtil来获取和释放redis资源,得到Jedis对象
-
/**
-
* Created by ${HeJD} on 2018/6/29.
-
*/
-
@Component
-
public class RedisUtil {
-
/**
-
* 日志记录
-
*/
-
private static final Logger LOG = LoggerFactory.getLogger(RedisUtil.class);
-
/**
-
* redis 连接池,这里jedisPool我们再之前spring配置中配置好了,交给spring管理,这里可以自动注入
-
*/
-
@Autowired
-
private JedisPool jedisPool;
-
public void setPool(JedisPool jedisPool) {
-
this.jedisPool = jedisPool;
-
}
-
/**
-
* 获取jedis
-
* @return
-
*/
-
public Jedis getResource(){
-
Jedis jedis =null;
-
try {
-
jedis =jedisPool.getResource();
-
} catch (Exception e) {
-
LOG.info("can't get the redis resource");
-
}
-
return jedis;
-
}
-
/**
-
* 关闭连接
-
* @param jedis
-
*/
-
public void disconnect(Jedis jedis){
-
jedis.disconnect();
-
}
-
/**
-
* 将jedis 返还连接池
-
* @param jedis
-
*/
-
public void returnResource(Jedis jedis){
-
if(null != jedis){
-
try {
-
jedisPool.returnResource(jedis);
-
} catch (Exception e) {
-
LOG.info("can't return jedis to jedisPool");
-
}
-
}
-
}
-
/**
-
* 无法返还jedispool,释放jedis客户端对象,
-
* @param jedis
-
*/
-
public void brokenResource(Jedis jedis){
-
if (jedis!=null) {
-
try {
-
jedisPool.returnBrokenResource(jedis);
-
} catch (Exception e) {
-
LOG.info("can't release jedis Object");
-
}
-
}
-
}
-
}
4.创建好RedisUtil后,我们来写一个对Redis操作的接口及其实现类(注意导包)
-
import java.util.Map;
-
/**
-
* Created by ${HeJD} on 2018/6/29.
-
*/
-
public interface RedisCacheStorage<K,V> {
-
/**
-
* 在redis数据库中插入 key 和value
-
* @param key
-
* @param value
-
* @return
-
*/
-
boolean set(K key,V value);
-
/**
-
* 在redis数据库中插入 key 和value 并且设置过期时间
-
* @param key
-
* @param value
-
* @param exp 过期时间
-
* @return
-
*/
-
boolean set(K key, V value, int exp);
-
/**
-
* 根据key 去redis 中获取value
-
* @param key
-
* @return
-
*/
-
V get(K key,Object object);
-
/**
-
* 删除redis库中的数据
-
* @param key
-
* @return
-
*/
-
boolean remove(K key);
-
/**
-
* 设置哈希类型数据到redis 数据库
-
* @param cacheKey 可以看做一张表
-
* @param key 表字段
-
* @param value
-
* @return
-
*/
-
boolean hset(String cacheKey,K key,V value);
-
/**
-
* 获取哈希表数据类型的值
-
* @param cacheKey
-
* @param key
-
* @return
-
*/
-
V hget(String cacheKey,K key,Object object);
-
/**
-
* 获取哈希类型的数据
-
* @param cacheKey
-
* @return
-
*/
-
Map<K,V> hget(String cacheKey,Object object);
-
}
-
import com.mmall.service.RedisCacheStorage;
-
import com.mmall.util.RedisUtil;
-
import net.sf.json.JSONObject;
-
import org.apache.commons.lang3.StringUtils;
-
import org.slf4j.*;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.stereotype.Service;
-
import redis.clients.jedis.Jedis;
-
import redis.clients.jedis.exceptions.JedisException;
-
import java.util.HashMap;
-
import java.util.Map;
-
/**
-
* Created by ${HeJD} on 2018/6/29.
-
*/
-
@Service("redisCacheStorage")
-
public class RedisCacheStorageImpl<V> implements RedisCacheStorage<String,V>{
-
//日志记录
-
private Logger log= LoggerFactory.getLogger(RedisCacheStorageImpl.class);
-
/**
-
* 默认过时时间
-
*/
-
private static final int EXPRIE_TIME =3600*24;
-
/**
-
* 获取Jedis相关操作
-
*/
-
@Autowired
-
private RedisUtil redisUtil;
-
@Override
-
public boolean set(String key, V value) {
-
return set(key,value,EXPRIE_TIME);
-
}
-
@Override
-
public boolean set(String key, V value, int exp) {
-
Jedis jedis=null;
-
if(StringUtils.isEmpty(key)){
-
return false;
-
}
-
try {
-
//获取jedis对象
-
jedis= redisUtil.getResource();
-
//使用对象转换为Json格式插入redis
-
JSONObject json = JSONObject.fromObject(value);//将java对象转换为json对象
-
String jsonValue = json.toString();//将json对象转换为json字符串
-
jedis.setex(key,exp,jsonValue);
-
}catch (Exception e){
-
//释放jedis对象
-
redisUtil.brokenResource(jedis);
-
log.info("client can't connect server");
-
return false;
-
}finally {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
return true;
-
}
-
}
-
@Override
-
public V get(String key,Object object) {
-
Jedis jedis=null;
-
V v=null;
-
if(StringUtils.isEmpty(key)){
-
log.info("redis取值,key为空");
-
return null;
-
}
-
try{
-
jedis=redisUtil.getResource(); //获取连接
-
String jsonValue=jedis.get(key); //从redis得到值,得到的是json字符串,因为我们之前插入的时候是使用的json字符串
-
if(StringUtils.isEmpty(jsonValue)){
-
return null;
-
}
-
JSONObject obj = new JSONObject().fromObject(jsonValue);//将json字符串转换为json对象
-
v = (V)JSONObject.toBean(obj,object.getClass());//将建json对象转换为你想要的java对象
-
return v;
-
}catch (Exception e){
-
//释放jedis对象
-
if(jedis!=null){
-
redisUtil.brokenResource(jedis);
-
}
-
log.info("client can't get value");
-
return null;
-
}finally {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
}
-
}
-
@Override
-
public boolean remove(String key) {
-
Jedis jedis=null;
-
try{
-
jedis=redisUtil.getResource();
-
if(StringUtils.isEmpty(key)){
-
log.info("redis取值,key为空");
-
return false;
-
}
-
jedis.del(key);
-
}catch (Exception e) {
-
//释放jedis对象
-
if(jedis!=null){
-
redisUtil.brokenResource(jedis);
-
}
-
log.info(" del fail from redis");
-
return false;
-
}finally{
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
return true;
-
}
-
}
-
@Override
-
public boolean hset(String cacheKey, String key, V value) {
-
Jedis jedis =null;
-
//将key 和value 转换成 json 对象
-
JSONObject json = JSONObject.fromObject(cacheKey);//将java对象转换为json对象
-
String jCacheKey = json.toString();//将json对象转换为json字符串
-
JSONObject json2 = JSONObject.fromObject(value);//将java对象转换为json对象
-
String jsonValue = json2.toString();//将json对象转换为json字符串
-
//操作是否成功
-
boolean isSucess =true;
-
if(StringUtils.isEmpty(jCacheKey)){
-
log.info("cacheKey is empty");
-
return false;
-
}
-
try {
-
jedis =redisUtil.getResource();
-
//执行插入哈希
-
jedis.hset(jCacheKey, key, jsonValue);
-
} catch (Exception e) {
-
log.info("client can't connect server");
-
isSucess =false;
-
if(null !=jedis){
-
//释放jedis 对象
-
redisUtil.brokenResource(jedis);
-
}
-
return false;
-
}finally{
-
if (isSucess) {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
}
-
return true;
-
}
-
}
-
@Override
-
public V hget(String cacheKey, String key,Object object) {
-
Jedis jedis =null;
-
V v =null;
-
JSONObject json = JSONObject.fromObject(cacheKey);//将java对象转换为json对象
-
String jCacheKey = json.toString();//将json对象转换为json字符串
-
if(StringUtils.isEmpty(jCacheKey)){
-
log.info("cacheKey is empty");
-
return null;
-
}
-
try {
-
//获取客户端对象
-
jedis =redisUtil.getResource();
-
//执行查询
-
String jsonValue = jedis.hget(jCacheKey, key);
-
//判断值是否非空
-
if(StringUtils.isEmpty(jsonValue)){
-
return null;
-
}else{
-
JSONObject obj = new JSONObject().fromObject(jsonValue);//将json字符串转换为json对象
-
v = (V)JSONObject.toBean(obj,object.getClass());//将建json对象转换为java对象
-
}
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
} catch (JedisException e) {
-
log.info("client can't connect server");
-
if(null !=jedis){
-
//redisUtil 对象
-
redisUtil.brokenResource(jedis);
-
}
-
}
-
return v;
-
}
-
@Override
-
public Map<String, V> hget(String cacheKey,Object object) {
-
JSONObject json = JSONObject.fromObject(cacheKey);//将java对象转换为json对象
-
String jCacheKey = json.toString();//将json对象转换为字符串
-
//非空校验
-
if(StringUtils.isEmpty(jCacheKey)){
-
log.info("cacheKey is empty!");
-
return null;
-
}
-
Jedis jedis =null;
-
Map<String,V> result =null;
-
V v=null;
-
try {
-
jedis =redisUtil.getResource();
-
//获取列表集合 因为插入redis的时候是jsonString格式,所以取出来key是String value也是String
-
Map<String,String> map = jedis.hgetAll(jCacheKey);
-
if(null !=map){
-
for(Map.Entry<String, String> entry : map.entrySet()){
-
if(result ==null){
-
result =new HashMap<String,V>();
-
}
-
JSONObject obj = new JSONObject().fromObject(entry.getValue());//将json字符串转换为json对象
-
v = (V)JSONObject.toBean(obj,object.getClass());//将建json对象转换为java对象
-
result.put(entry.getKey(), v);
-
}
-
}
-
} catch (JedisException e) {
-
log.info("client can't connect server");
-
if(null !=jedis){
-
//释放jedis 对象
-
redisUtil.brokenResource(jedis);
-
}
-
}
-
return result;
-
}
5.最后我们来测试一下,注意实际开发中肯定是再service层调用redis的操作接口,我这里写个简单的单元测试
第二种:序列化后存入redis, 我这里用SerializeUtil,不过我推荐使用ProtoBuff更好
-
/**
-
* Created by ${HeJD} on 2018/6/29.
-
*/
-
@RunWith(SpringJUnit4ClassRunner.class)
-
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
-
public class RedisCacheStorageTest {
-
@Autowired
-
private RedisCacheStorage<String,User> redisCacheStorage;
-
@Test
-
public void testSetGet() throws Exception {
-
System.out.print("开始执行测试");
-
User user=new User();
-
user.setUsername("admin7");
-
user.setPassword("admin8");
-
redisCacheStorage.set("Akey7",user);
-
User user2= redisCacheStorage.get("Akey7",new User());
-
System.out.print("======="+user2.getUsername()+"====="+user2.getPassword());
-
}
代码在上一种方式的基础之上,我这里只写一些新的文件和需要修改的地方
1.首先我们需要一个序列化类
public class SerializeUtil {
/*
* 序列化
* */
public static byte[] serizlize(Object object){
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
3.最后测试的代码是一样的
(注意两个地方:1.这里是多实现,要用Qualifier指定注入的bean 2.序列化的方式实体类要实现Serializable接口)
2.我们需要对redis操作接口的实现类修改为另一种方式,我这里新建一个RedisCacheStorageImpl2来做对比
-
@RunWith(SpringJUnit4ClassRunner.class)
-
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
-
public class RedisCacheStorageTest {
-
@Autowired
-
@Qualifier("redisCacheStorage2")
-
private RedisCacheStorage<String,User> redisCacheStorage;
-
@Test
-
public void testSet() throws Exception {
-
System.out.print("开始执行测试");
-
User user=new User();
-
user.setUsername("admin9");
-
user.setPassword("admin12");
-
redisCacheStorage.set("Akey9",user);
-
User user2= (User) redisCacheStorage.get("Akey9",new User());
-
System.out.print("======="+user2.getUsername()+"====="+user2.getPassword());
-
}
-
}
-
package com.mmall.service.impl;
-
/**
-
* Created by ${HeJD} on 2018/7/1.
-
*/
-
import com.mmall.service.RedisCacheStorage;
-
import com.mmall.util.RedisUtil;
-
import com.mmall.util.SerializeUtil;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.stereotype.Service;
-
import org.springframework.util.StringUtils;
-
import redis.clients.jedis.Jedis;
-
import redis.clients.jedis.exceptions.JedisException;
-
import java.util.HashMap;
-
import java.util.Map;
-
/**
-
* Created by ${HeJD} on 2018/6/29.
-
*/
-
@Service("redisCacheStorage2") //这里注入的名称不能相同,方便程序识别
-
public class RedisCacheStorageImpl2<V> implements RedisCacheStorage<String,V> {
-
//日志记录
-
private Logger log= LoggerFactory.getLogger(RedisCacheStorageImpl2.class);
-
/**
-
* 默认过时时间
-
*/
-
private static final int EXPRIE_TIME =3600*24;
-
/**
-
* 获取Jedis相关操作
-
*/
-
@Autowired
-
private RedisUtil redisUtil;
-
@Override
-
public boolean set(String key, V value) {
-
return set(key,value,EXPRIE_TIME);
-
}
-
@Override
-
public boolean set(String key, V value, int exp) {
-
Jedis jedis=null;
-
if(StringUtils.isEmpty(key)){
-
return false;
-
}
-
try {
-
//获取jedis对象
-
jedis= redisUtil.getResource();
-
//序列化对象后插入到redis
-
//我们需要使用 public String setex(byte[] key, int seconds, byte[] value),所以将key.getBytes()
-
jedis.setex(key.getBytes(),exp, SerializeUtil.serizlize(value));
-
}catch (Exception e){
-
//释放jedis对象
-
redisUtil.brokenResource(jedis);
-
log.info("client can't connect server");
-
return false;
-
}finally {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
return true;
-
}
-
}
-
@Override
-
public V get(String key,Object object) {
-
Jedis jedis=null;
-
V v=null;
-
if(StringUtils.isEmpty(key)){
-
log.info("redis取值,key为空");
-
return null;
-
}
-
try{
-
jedis=redisUtil.getResource(); //获取连接
-
//我们存入的时候使用的是key.getBytes(),所以取的时候也要使用它的key数组
-
byte valueByte[]=jedis.get(key.getBytes()); //从redis得到值
-
if(valueByte.length<=0){
-
return null;
-
}
-
//反序列化取出我们的数据
-
v=(V)SerializeUtil.deserialize(valueByte); //将值转换为我们插入redis之前的数据类型
-
return v;
-
}catch (Exception e){
-
//释放jedis对象
-
if(jedis!=null){
-
redisUtil.brokenResource(jedis);
-
}
-
log.info("client can't get value");
-
return null;
-
}finally {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
}
-
}
-
@Override
-
public boolean remove(String key) {
-
Jedis jedis=null;
-
try{
-
jedis=redisUtil.getResource();
-
if(StringUtils.isEmpty(key)){
-
log.info("redis取值,key为空");
-
return false;
-
}
-
jedis.del(key.getBytes());
-
}catch (Exception e) {
-
//释放jedis对象
-
if(jedis!=null){
-
redisUtil.brokenResource(jedis);
-
}
-
log.info(" del fail from redis");
-
return false;
-
}finally{
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
return true;
-
}
-
}
-
@Override
-
public boolean hset(String cacheKey, String key, V value) {
-
Jedis jedis =null;
-
byte valueDate[]= SerializeUtil.serizlize(value);
-
//操作是否成功
-
boolean isSucess =true;
-
if(StringUtils.isEmpty(cacheKey)){
-
log.info("cacheKey is empty");
-
return false;
-
}
-
try {
-
jedis =redisUtil.getResource();
-
//执行插入哈希
-
//public Long hset(byte[] key, byte[] field, byte[] value)
-
jedis.hset(cacheKey.getBytes(),key.getBytes(),valueDate);
-
} catch (Exception e) {
-
log.info("client can't connect server");
-
isSucess =false;
-
if(null !=jedis){
-
//释放jedis 对象
-
redisUtil.brokenResource(jedis);
-
}
-
return false;
-
}finally{
-
if (isSucess) {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
}
-
return true;
-
}
-
}
-
@Override
-
public V hget(String cacheKey, String key,Object object) {
-
Jedis jedis =null;
-
V v =null;
-
if(cacheKey.getBytes().length<=0){
-
log.info("cacheKey is empty");
-
return null;
-
}
-
try {
-
//获取客户端对象
-
jedis =redisUtil.getResource();
-
//执行查询
-
byte valueDate[] = jedis.hget(cacheKey.getBytes(), key.getBytes());
-
//判断值是否非空
-
if(valueDate.length<0){
-
return null;
-
}else{
-
//反序列化拿到数据
-
v= (V)SerializeUtil.deserialize(valueDate);
-
return v;
-
}
-
} catch (JedisException e) {
-
log.info("client can't connect server");
-
if(null !=jedis){
-
//redisUtil 对象
-
redisUtil.brokenResource(jedis);
-
}
-
}finally {
-
//返还连接池
-
redisUtil.returnResource(jedis);
-
}
-
return v;
-
}
-
@Override
-
public Map<String, V> hget(String cacheKey,Object object) {
-
//非空校验
-
if(StringUtils.isEmpty(cacheKey)){
-
log.info("cacheKey is empty!");
-
return null;
-
}
-
Jedis jedis =null;
-
Map<String,V> result =new HashMap<String,V>();
-
try {
-
jedis =redisUtil.getResource();
-
//获取列表集合 因为插入redis的时候是key和value都是字节数组,所以返回的结果也是字节数组
-
Map<byte[], byte[]> map= jedis.hgetAll(cacheKey.getBytes());
-
if(null !=map){
-
for(Map.Entry<byte[], byte[]> entry : map.entrySet()){
-
result.put(new String(entry.getKey()),(V)SerializeUtil.deserialize(entry.getValue()));
-
}
-
}
-
} catch (JedisException e) {
-
log.info("client can't connect server");
-
if(null !=jedis){
-
//释放jedis 对象
-
redisUtil.brokenResource(jedis);
-
}
-
}
-
return result;
-
}
-
}
-
try {
-
baos = new ByteArrayOutputStream();
-
oos = new ObjectOutputStream(baos);
-
oos.writeObject(object);
-
byte[] bytes = baos.toByteArray();
-
return bytes;
-
} catch (Exception e) {
-
e.printStackTrace();
-
}finally {
-
try {
-
if(baos != null){
-
baos.close();
-
}
-
if (oos != null) {
-
oos.close();
-
}
-
} catch (Exception e2) {
-
e2.printStackTrace();
-
}
-
}
-
return null;
-
}
-
/*
-
* 反序列化
-
* */
-
public static Object deserialize(byte[] bytes){
-
ByteArrayInputStream bais = null;
-
ObjectInputStream ois = null;
-
try{
-
bais = new ByteArrayInputStream(bytes);
-
ois = new ObjectInputStream(bais);
-
return ois.readObject();
-
}catch(Exception e){
-
e.printStackTrace();
-
}finally {
-
try {
-
} catch (Exception e2) {
-
e2.printStackTrace();
-
}
-
}
-
return null;
-
}
-
}
-
}
-
}