SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

                      很多时候、我们都需要用java连接客服端jedis来操作Linux系统下的Reids集群、那么今天在搭建集群的时候遇到一些麻烦的问题、避免同行不要在犯、

                       首先问题是这样的、由于对redis的理解太抽象化、所以使用图形界面来更好的理解、我相信很多人跟我有同感、

                                       ——SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis


 2018-01-11 20:43:08 : Connection: AUTH ERROR

2018-01-11 20:43:09 : Connection: AUTH

2018-01-11 20:43:09 : Connection: ddd > connected

2018-01-11 20:43:09 : Connection: ddd > [runCommand] ping

2018-01-11 20:43:09 : Connection: ddd > [runCommand] ping -> response received : 0

2018-01-11 20:43:09 : Connection: AUTH ERROR


     下载地址:

    问题:在跟图形界面连接时、遇到这个问题、原因是没有登录密码、


  然后我们需要在:Linux 中redis 配置文件  redis.conf 中 设置

   SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

           这样设置密码之后、就可以连接、

                    SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis


               后者、

                       在eclipse中测试、可以ping通过

              SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis


               接下来最重要的东西:

                         我们在SpringMVC+Mybits+Spring、以及Maven 开发中需要配置

       

1.jedis

首先,需要添加jedis:


<!--jedis-->
<dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.8.0</version>
</dependency>

2.applicationContext-jedis.xml

然后,springmvc完成基本配置。添加jedispool的bean即可。在spring容器中添加applicationContext-jedis.xml:

在applicationContext-jedis.xml中添加:

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
<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-3.2.xsd">
    <!-- 加载配置属性文件 -->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:db.properties" />

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="300"/> <!--最大能够保持idel状态的对象数-->
        <property name="maxTotal" value="60000"/><!--最大分配的对象数-->
        <property name="testOnBorrow" value="true"/><!--当调用borrow Oject方法时,是否进行有效性检查-->
    </bean>

    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg index="0" ref="jedisPoolConfig"/>
        <constructor-arg index="1" value="${redis.host}"/>
        <constructor-arg index="2" value="${redis.port}" type="int"/>
        <constructor-arg index="3" value="${redis.timeout}" type="int"/>
        <constructor-arg index="4" value="${redis.auth}"/>
    </bean>
</beans>

注解:参考的源码中的jedisPool配置只有三个参数:config,host,port。我复制后的结果总是getResource失败,因为我的redis添加了auth,所以猜测是不是没通过auth的原因。于是打开JedisPool的源码:

SpringMVC+Mybits+Spring___中使用Jedis以及操作RedisView Code

看到有password的参数配置,如果没有配置的话默认为null。到这一步我便没有往下深入看了,因为我连接的redis中有auth,原谅我的不求甚解。于是,我接着配置timeout和auth。timeout直接还是源码的默认值。后面的代码测试通过。在这里我了解到spring的bean注入的几个参数含义:比如property表示属性注入,constructor表示构造函数的参数注入。

 

为了更清楚的表达,redis要设置db,配置文件参数也做一下改动:

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="300" /> <!-- 最大能够保持idel状态的对象数  -->
        <property name="maxTotal" value="60000" /> <!-- 最大分配的对象数 -->
        <property name="testOnBorrow" value="true" /> <!-- 当调用borrow Object方法时,是否进行有效性检查 -->
    </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.password}'!=''?'${redis.password}':null}" />
        <constructor-arg name="database" value="${redis.db.index}" type="int" />
    </bean>
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

最后一项参数是选择redis的db,我认为通常默认连接的都是redis的0,那么我们的开发环境为了不冲突,应该另外设置。但JedisPool并没有只有指定db的构造函数,所以选择了这个构造函数。唯一的问题是,默认我们的redis是没有密码的,那么这里也填null而不是空字符串哦。所以,这里使用spring spEL表达式来填充空。对应的配置文件如下:

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
#redis settings
redis.keyPrefix=wz
redis.host=127.0.0.1
redis.port=6379
redis.timeout=2000
#注意,如果没有password,此处不设置值,但这一项要保留
redis.password=
redis.db.index=1

3.  JedisUtil

 3.1 getResource

上面设置好了JedisPool,这里就要获取jedis。然后就可以利用jedis进行操作了。

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
 1  /**
 2      * 获取资源
 3      * @return
 4      */
 5     public static Jedis getResource() {
 6         Jedis jedis = null;
 7         try {
 8             jedis = jedisPool.getResource();
 9             logger.debug("getResource:{}",jedis);
10         } catch (Exception e) {
11             logger.error("getResource:{}",e);
12             if (jedis!=null)
13             jedis.close();
14             throw  e;
15         }
16         return jedis;
17     }
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

但是,为了更加自定义的设置db,这里也可以加一个db的选择:

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
    public static Jedis getResource() throws JedisException {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.select(Integer.parseInt(DB_INDEX));
//            logger.debug("getResource.", jedis);
        } catch (JedisException e) {
            logger.warn("getResource.", e);
            returnBrokenResource(jedis);
            throw e;
        }
        return jedis;
    }
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

 

 

3.1.1设置prefix

为了我们的key与其他app不冲突,我们最后为我们key统一增加一个标识,这种做法类似选择一个表。

private static String setPrefix(String key) {
    key=KEY_PREFIX+"_"+key;
    return key;
}

在任何使用到redis的地方,配置key的prefix。比如get 和 set:

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
    public static String get(String key) {
        key = setPrefix(key);
        String value = null;
        Jedis jedis = null;
        try {
            jedis = getResource();
            if (jedis.exists(key)) {
                value = jedis.get(key);
                value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;
                logger.debug("get {} = {}", key, value);
            }
        } catch (Exception e) {
            logger.warn("get {} = {}", key, value, e);
        } finally {
            returnResource(jedis);
        }
        return value;
    }
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
    public static String set(String key, String value, int cacheSeconds) {
        key = setPrefix(key);
        String result = null;
        Jedis jedis = null;
        try {
            jedis = getResource();
            result = jedis.set(key, value);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
            logger.debug("set {} = {}", key, value);
        } catch (Exception e) {
            logger.warn("set {} = {}", key, value, e);
        } finally {
            returnResource(jedis);
        }
        return result;
    }
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

 

 

 

3.2 Object对象的缓存

通过使用jedis基本可以完成任何操作了。这里添加一个缓存对象的功能。java对象的缓存利用序列化实现,因此,需要缓存的对象必须实现了serializable接口。关于如何序列化,参考:将对象序列化和反序列化

SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis
 1   /**
 2      * 设置缓存
 3      * @param key String
 4      * @param value Object对象
 5      * @param cacheSeconds 超时时间,0为不超时
 6      * @return
 7      */
 8     public static String setObject(String key,Object value,int cacheSeconds){
 9         String result = null;
10         Jedis jedis = null;
11         try {
12             jedis = getResource();
13             result = jedis.set(getBytesKey(key),toBytes(value));
14             if (cacheSeconds!=0){
15                 jedis.expire(key,cacheSeconds);
16             }
17             logger.debug("setObject {}={}",key,value);
18         } catch (Exception e) {
19             logger.warn("setObject {}  失败:{}",key,e);
20         } finally {
21             jedis.close();
22         }
23         return result;
24     }
25 /**
26      * 获取缓存
27      * @param key
28      * @return 对象(反序列化)
29      */
30     public static Object getObject(String key){
31         Object value = null;
32         Jedis jedis = null;
33         try {
34             jedis = getResource();
35             byte[] bytes = jedis.get(getBytesKey(key));
36             value =  toObject(bytes);
37             logger.debug("getObject {}={}",key,value);
38         } catch (Exception e) {
39             logger.warn("getObject {}错误:{}",key,e.getMessage());
40             e.printStackTrace();
41         } finally {
42             jedis.close();
43         }
44         return value;
45     }
46  /**
47      * 将key转换为byte[]
48      * @param object
49      * @return
50      */
51     private static byte[] getBytesKey(Object object) {
52         if(object instanceof String){
53             return StringUtils.getBytes((String) object);
54         }else {
55             return ObjectUtils.serialize(object);
56         }
57     }
58 
59     /**
60      * Object转换为byte[]类型
61      * @param value Object对象
62      * @return byte[]数组
63      */
64     private static byte[] toBytes(Object value) {
65         return ObjectUtils.serialize(value);
66     }
67 
68     /**
69      * byte[]转换为object
70      * @param bytes
71      * @return
72      */
73     private static Object toObject(byte[] bytes) {
74         return ObjectUtils.unserialize(bytes);
75     }
SpringMVC+Mybits+Spring___中使用Jedis以及操作Redis

3.3 ObjectList对象缓存

我们平时用到的list基本都是ObjectList,即list的元素为object而不是String。这样就需要特定方法来缓存了。

采用同样的方式,将object序列化为字节数组,然后存储起来。取出的时候再反序列化,因此object必须实现了serializable接口,而且static的成员不能序列化或者说序列化的结果为默认值。原因参考:将对象序列化和反序列化