挖坑记录-redistemplate hincrby

阿凡达2018-07-10 14:08

HINCRBY

浏览数业务

  • 使用了redis
  • spring中的RedisTemplate
    • 增加浏览数量
      //简单的获取浏览数量,然后加一
      Long previewNumber = getPreviewNumber(sourceId, previewType);
      String key = getKey(previewType, sourceId);
      previewNumber = previewNumber < 0 ? 0L : previewNumber + 1;
      redisTemplate.opsForHash().put(PRIVIEW_KEY, key, previewNumber);
      
  • 获取浏览数

    //获取缓存数量,不存在,设置为-1
    private Long getCacheNumber( Map<String, Long> map, PreviewType previewType,Object sourceId) {
      String key = getKey(previewType, sourceId.toString());
      Long number = map.get(key);
      return null == number ? -1 :number;
    }
    //获取如果cacheNumber小于0
    Long cacheNumber = getCacheNumber(map,previewType, sourceId);
    if (cacheNumber < 0) {
      cacheNumber = 0L;
      Preview preview = previewDao.getPreview(previewType.getCode(), sourceId);
      if (null != preview) {
          number = preview.getNumber();
          //缓存不存在,数据库存在, 添加缓存
          hashOperations.put(PRIVIEW_KEY, getKey(previewType, sourceId), number);
      } else {
          //没有浏览记录,增加缓存为 0的记录
          hashOperations.put(PRIVIEW_KEY, getKey(previewType, sourceId), number);
    
      }
    }
    return cacheNumber;
    

    这什么烂代码!是的,改下,起码用redis 的 increment 来做增加数量

开始给自己挖坑

做了简单的修改

Long number =  redisTemplate.opsForHash().increment(THUMB_UP_KEY, getKey(previewType, sourceId), 1);

error

Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR hash value is not an integer 调用个简单的方法也报错?

debug


jedis直接调用了redis的hincrby命令,没什么可说的。

然后直接调用getIntegerReply获取redis服务器返回的信息

直接是minus_byte类型

抛出了异常,发生了什么?

找到了如下资料

https://jira.spring.io/browse/DATAREDIS-103

应该是和序列化有关系的。 使用redis 会配置对应的key和value序列化方式。

例如:

RedisTemplate<String, String> temp = new RedisTemplate<String, String>();
temp.setKeySerializer(new StringRedisSerializer());
temp.setValueSerializer(new StringRedisSerializer());

但是不应该啊,存储到redis使用什么序列化方式,获取时肯定是用对应方式反序列化嘛, 问题应该不是出在这里。

代码注意到这里

spring直接调用了connection,并没有对delta进行序列化操作,接着点进去看到,

jedis提供的connection直接转换成String,然后使用String的getBytes();方法

然后看了下对应key再redis的数据

搞了个新key

原因很明显了

  • increment 会直接对值进行做增加操作,不会使用对应的redistemplate中设置的序列化方式
  • 原来redis中的旧数据是通过redisTemplate.opsForHash().put进去的,会先通过设置的序列化方式进行序列化,
  • 后面对key进行increment redis没办法对应value转成long进行操作,所以返回了ERR hash value is not an integer异常信息。

    删除旧数据就可以了吧。

    清空redis数据后

    //这里出现了异常
    hashOperations.entries(PRIVIEW_KEY)
    

    org.springframework.data.redis.serializer.SerializationException: fst-deserialization-error; nested exception is java.io.IOException: java.lang.NullPointerException

    原因和上面大同小异,这里获取的时候依然会进行序列化操作,而且increment设置的值是没有进行对应序列化的。这里是FST 进行反序列化时异常。

    总结

  • increment使用要避免和其他需要经过序列化的操作混用。
  • 对用到的东西要有全面的了解,才能避免各种坑。
  • 为什么会这么累,就是喜欢给自己挖坑。

本文来自网易实践者社区,经作者张昌路授权发布。