Java使用redis:将数据插入redis缓存的方式

背景:

当redis里面需要存储 “key-字符串,value-对象” 时,是不能直接存对象,而是需要将序列化转换为JSON后的对象存进redis。

redis没有实现内部序列化对象的功能,所以需要自己提前序列化对象及转换为Json对象。

序列化介绍:

序列化的方法有很多,比如java原生序列化(需要实现Serializable接口)、json序列化、protobuff序列化。

protobuff序列化:告诉我对象的class,内部有schema来描述你的class是什么结构,class必须有get/set方法这种标准的类,而不是string等类

关于Serializable和protobuff序列化的介绍在我的上一篇文章:点击打开链接

由于之前对redis有很大兴趣,在使用redis当做数据缓存;所以趁着这些天的时间,自己写了一个将数据插入redis的demo;这里仅供自己后期学习笔记参考,若有不对的地方,请轻拍砖!

第一种:将数据对象转换为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的操作接口,我这里写个简单的单元测试
/**
 * 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());
     
    }
}
结果:

第二种:序列化后存入redis, 我这里用SerializeUtil,不过我推荐使用ProtoBuff更好

代码在上一种方式的基础之上,我这里只写一些新的文件和需要修改的地方
1.首先我们需要一个序列化类
public class SerializeUtil {
    /*
     * 序列化
     * */
    public static byte[] serizlize(Object object){
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        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;
    }
}
2.我们需要对redis操作接口的实现类修改为另一种方式,我这里新建一个 RedisCacheStorageImpl2来做对比
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;
    }
}
3.最后测试的代码是一样的
(注意两个地方:1.这里是多实现,要用Qualifier指定注入的bean 2.序列化的方式实体类要实现Serializable接口)
@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());
    }
}

结果:


redis中的结果也贴一下吧:

  1. 127.0.0.1:6379> keys *
    1) "Akey9"
    2) "Akey7"
    127.0.0.1:6379> get Akey7
    "{\"password\":\"admin8\",\"role\":0,\"answer\":\"
    ime\":null,\"phone\":\"\",\"updateTime\":null,\"id
    \":\"admin7\"}"
    127.0.0.1:6379> get Akey9
    "\xac\xed\x00\x05sr\x00\x13com.mmall.pojo.User,\aC
    x06answert\x00\x12Ljava/lang/String;L\x00\ncreateT
    x00\x05emailq\x00~\x00\x01L\x00\x02idt\x00\x13Ljav
    q\x00~\x00\x01L\x00\x05phoneq\x00~\x00\x01L\x00\bq
    roleq\x00~\x00\x03L\x00\nupdateTimeq\x00~\x00\x02L
    ppppt\x00\aadmin12ppppt\x00\x06admin9"
    127.0.0.1:6379>
  2. 好了以上

猜你喜欢

转载自blog.csdn.net/eeeeasy/article/details/80873082