关于ValueOperations的increment方法的解惑

    Java,操作Redis,标配Jedis,如果加上Spring,自然选用Spring Data Redis(简称“sdr”)。

    最近在开发中,使用Redis来实现数据点击量的统计存储功能。为什么使用Redis?点击量之类的功能,需要频繁触发更新操作,而且高并发访问时,还需要考虑操作冲突导致数据不一致的问题。而Redis是内存型存储,相比关系型数据库,操作更快,避免了频繁的文件写操作。更重要的是,Redis中有个INCR和INCRBY命令,都可以实现值递增的原子性操作,方便了解决了高并发时的冲突问题。

    Redis手册中的命令说明很详尽,还有Redis中文命令参考的网站可供使用,在此感谢无私的翻译人员。如下:

Redis中文参考手册

    sdr中针对redis的命令,一一提供了对应的方法可供使用,结合redis命令参考sdr的api,很容易上手。但唯一不足地是,sdr提供的api太简略了,只提供了函数和参数,参数的说明、返回值的说明、异常情况的说明统统没有,这个只能自己在实践的过程中用代码来认知了。

    sdr中提供了一个ValueOperations的接口来针对Redis中的Key-Value的命令操作。通过粗略追踪源码的手段,可以大概了解到,sdr框架操作Redis的实质,是和Redis服务通信,告知Redis服务执行指定的命令。ValueOperations中有increment方法,本质上是向Redis服务发送的INCRBY命令。当然要实现点击量递增的功能,需要使用ValueOperations的increment方法。

    Redis采用Key-Value的格式实现了多种结构的数据,例如List、Set等。但Redis中的Key和Value存储的都是字符串,而Java是面向对象的语言,大部分情况下操作数据也都是对象,那么Java与Redis的结合手段自然是序列化了。sdr提供了丰富的序列化策略,所以在配置sdr时,可以显示地指定Key和Value的序列化器,如下代码所示。这部分不了解的同志可以搜索相关的内容去了解,这里不再做过多说明。

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
    </bean>

    如果没有显示指定Key或Value的序列化器,默认采用JdkSerializationRedisSerializer。StringRedisSerializer将数据存储为正常的字符串,而且JdkSerializationRedisSerializer则是将数据存储为一串序列字符串,还需通过反序列化才能得到正常的字符串。

    当在使用ValueOperations之类的接口时,值得注意的是,接口是使用泛型的,如ValueOperations<K,V>,起初实现点击量递增,自然选用了ValueOperations<String,Long>的方式,点击量嘛,当然是整数喽。可就在调用increment方法时出现问题了,提示“ERR value is not an integer or out of range”。Redis手册中已经给出了很明确的说明,如下:

关于ValueOperations的increment方法的解惑_第1张图片

    在递增之前,由于使用ValueOperations的set方法为点击量设置了初始值,Key的序列化器采用的是JdkSerializationRedisSerializer,其将初始值变成了序列化字符串存入了Redis,而Redis执行INCRBY命令时是无法识别序列化字符串为整数的,所以会提示错误。

    有人提出一个很奇怪的现象,如果不使用set方法设置点击量的初始值,直接调用increment方法,Redis中存入的是正常的数字字符串,没有被序列化!这个现象仔细想想,跟sdr没有半毛钱关系的,更扯不到序列化。看上图中的一句说明,“如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作”。在点击量的Key不存在时,直接调用increment方法,递增量的初始值是由Redis生成的,根本没有走sdr的序列化策略,又何来序列化。

    那说了这么多,点击量的递增到底如何来解决呢?我得出的结论是,在使用ValueOperations的increment功能时,设置Value的序列化器为StringRedisSerializer,这样存入Redis的值即为可识别的数字字符串了。可以在配置文件中配置,也可以在代码中动态的指定Value的序列化器,下面贴出配置文件中的配置方式:

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
          p:connectionFactory-ref="jedisConnectionFactory">
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
    </bean>

参考链接:

http://docs.spring.io/spring-data/redis/docs/1.4.0.M1/reference

http://shift-alt-ctrl.iteye.com/blog/1887370

你可能感兴趣的:(redis,spring,increment,Serialize,valueOperations)