解决RedisTemplate调用increment报错问题

使用spring redis的increment方法时,报错:

nested exception is redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range

一、INCRBY key increment

INCRBY key increment介绍如下:

将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。

# key 存在且是数字值

redis> SET rank 50
OK

redis> INCRBY rank 20
(integer) 70

redis> GET rank
"70"

# key 不存在时

redis> EXISTS counter
(integer) 0

redis> INCRBY counter 30
(integer) 30

redis> GET counter
"30"

# key 不是数字值时

redis> SET book "long long ago..."
OK

redis> INCRBY book 200
(error) ERR value is not an integer or out of range

二、错误分析

报错的初始使用方法为

public Long incr(String key, long delta){
 return commonRedisTemplate.opsForValue().increment(key, delta);
}

通过上面分析可以发现,错误原因是key对应的值不为数字,不能进行递增操作。通过查看RedisTemplate源码发现,其默认的序列化器为JdkSerializationRedisSerializer,猜想是否是序列化器进行序列化的时候,将key对应的value序列化为了字符串。

下面是RedisTemplate类部分源码

 boolean defaultUsed = false;
 if (defaultSerializer == null) {
  defaultSerializer = new JdkSerializationRedisSerializer(
  classLoader != null ? classLoader : this.getClass().getClassLoader());
 }

 if (enableDefaultSerializer) {
  if (keySerializer == null) {
   keySerializer = defaultSerializer;
   defaultUsed = true;
  }
 if (valueSerializer == null) {
  valueSerializer = defaultSerializer;
  defaultUsed = true;
 }
 if (hashKeySerializer == null) {
  hashKeySerializer = defaultSerializer;
  defaultUsed = true;
 }
 if (hashValueSerializer == null) {
  hashValueSerializer = defaultSerializer;
  defaultUsed = true;
 }

通过查看源码可以发现,

1.GenericJackson2JsonRedisSerializer、Jackson2JsonRedisSerializer是先将对象转为json,然后再保存到redis,所以,1在redis中是字符串1,所以无法进行加1。

2.JdkSerializationRedisSerializer使用的jdk对象序列化,序列化后的值有类信息、版本号等,所以是一个包含很多字母的字符串,所以根本无法加1。

3.GenericToStringSerializer、StringRedisSerializer将字符串的值直接转为字节数组,所以保存到redis中是数字,所以可以进行加1

修正后使用方法为

public Long incr(String key, long delta){
 ValueOperations<String, String> operations = commonRedisTemplate.opsForValue();
 commonRedisTemplate.setKeySerializer(new StringRedisSerializer());
 commonRedisTemplate.setValueSerializer(new StringRedisSerializer());
 return operations.increment(key, delta);
}

补充知识:生成履行行行号及RedisTemplate使用碰坑

title: 生成履行行行号及RedisTemplate使用碰坑

date: 2020-10-24 13:40

updated: 2020-10-24 13:30

categories:

搬砖笔记

java

tags:

java

redis

大致实现逻辑

后台写一个通用方法,参数为履行合同业务类型和公司代码,返回值为16位的履行行行号。

生成规则:履行合同业务类型1位+公司代码4位+年份2位+流水号9位(每个公司每年的流水号都从1开始)。例如:1 0021 20 000000001。

用子项目编码+公司代码+年份做Redis键,值为流水号。

流水号:由于直接用java代码生成在集群环境会有问题,故采用redisTemplate的increment(key,delta)方法生成,初次调用该方法会返回1。

格式化:redis返回的是自增的数字,需要格式化为9位流水号。java代码如下:

String.format("%09d",serialNumber);

RedisTemplate使用碰坑

redisTemplate. opsForValue(). set(key,value)这种方式存入Redis后会把数字型的值转为字符串,以后调用increment(key,delta)方法报错。

原因是底层采用了JdkSerializationRedisSerializer序列化机制。

解决方法有如下两种:

采用序列化方式

redisTemplate.setKeySerializer(new StringRedisSerializer());

redisTemplate.setValueSerializer(new StringRedisSerializer());

赋值方法也要改(值为字符串),例如:

redisTemplate. opsForValue().set(key,"0")

使用StringRedisTemplate

Long serialNumber = stringRedisTemplate. opsForValue().increment(key,1);

以上这篇解决RedisTemplate调用increment报错问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 使用Redis incr解决并发问题的操作

    项目背景: 1.新增问题件工单,工单中有工单编码字段,工单编码字段的规则为 "WT"+yyyyMMdd+0000001. 2.每天的工单生成量是30W,所以会存在并发问题 解决思路: 1.首先乐观的认为redis不会宕机,对应的缓存不会被清除(除非人为操作,人为操作会有独立的补救办法) 2.将工单编码存到缓存中(redis),其值只存"WT"+yyyyMMdd后面的数字部分: 对应的key为:key标识+yyyyMMdd,即每天一个key 3.每次生成工单编码时,先

  • 利用spring-data-redis实现incr自增的操作

    应该有不少人在使用spring-data-redis时遇到各种各样的问题.反正我是遇到了. 由于是隔了一段时间才写的本篇博客,也懒得去重现哪些错误场景了,下面凭着记忆写了几个我遇到的问题: redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range 使用的RedisTemplate,做读写操作时候,都是要经过序列化和反序列化. 这时你使用redisTemplate.o

  • redis incr和incrBy的使用说明

    最近用incr和incrBy在接口里做了下埋点统计每天请求总数,这两个命令还是挺好用的,先说下这俩命令吧 注:redis后台服务是串行的单线程执行,不存在并发,即多线程调用Incr/incrby方法,在redis服务器上仍然是串行的单线程执行,不存在并发,所以这俩命令都是原子自增.线程安全的. 1.Incr 命令 (菜鸟教程) Redis Incr 命令将 key 中储存的数字值增一. 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作. 如果值包含错误的类

  • 使用redis的increment()方法实现计数器功能案例

    一直知道redis可以用来实现计数器功能,但是之前没有实际使用过,昨天碰到一个需求:用户扫码当天达到20次即提示:当日扫码次数达到上限! 当时就想到使用redis的递增方法increment()来实现计数器功能,一定要注意redisTemplate和stringRedisTemplate的使用 首先设置key: 该key我使用了用户id和当天日期作为key的一部分,date:xxxx-xx-xx格式,这样一来该用户在第二天扫码的时候又是一个新key,因为日期不同了 设置key的过期时间: 实现计

  • 解决RedisTemplate调用increment报错问题

    使用spring redis的increment方法时,报错: nested exception is redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range 一.INCRBY key increment INCRBY key increment介绍如下: 将 key 所储存的值加上增量 increment .如果 key 不存在,那么 key 的值会先被初始化为

  • 解决java执行cmd命令调用ffmpeg报错Concat error - No such filter '[0,0]'问题

    最近公司有一个公交项目,要生成报站语音,采用的是 报站前缀 + 站点名 + 报站后缀,3个MP3文件拼接的方式,拼接成一个完整的语音,且需要转码率和比特率,使用到了ffmpeg. 去网上找了一些ffmpeg相关的命令,参考: 安装命令参考 音频转码: ffmpeg -i **.mp3 -ar 8000 -ac 2 -y -b:a 32k -vol 400 **.mp3 音频拼接: //音频拼接 (1) ffmpeg -i "concat:test4.mp3|180_out.mp3" -

  • docker容器调用yum报错的解决办法

    dockerfile里或者在容器里执行yum,报错,找不到源(invalid baseurl xxx),但是宿主机上执行yum是没问题的啊,为什么? 因为不论是dockerfile使用RUN关键字执行yum还是直接进入到容器里面执行yum,它们都是使用的docker镜像里面的源(CentOS是在路径/etc/yum.repo.d/CentOS-Base.repo),所以你要把宿主机上的同路径下的源拷贝到容器里面,然后docker commit一个新的"基础镜像",这个时候使用docke

  • vue 解决循环引用组件报错的问题

    做项目时遇到使用循环组件,因为模式一样,只有数据不一样.但是按照普通的组件调用格式来做时报错,错误信息为Unknown custom element: <pop> - did you register the component correctly? For recursive components, make sure to provide the "name" option. 查询了官方文档,还有其他的资料,发现是循环调用组件时,组件比vue实例后创建,官方文档里写组件

  • vue如何解决循环引用组件报错的问题

    问题由来 最近在做项目的时候遇到使用循环组件,因为模式一样,只有数据不一样.按照普通组件调用格式来做的时候总是报错,错误信息为[Vue warn]: Unknown custom element: <selfile> - did you register the component correctly? For recursive components, make sure to provide the "name" option. 解决方案 查询了网上各种资料之后,发现是

  • 解决TensorFlow模型恢复报错的问题

    错误信息 Attempting to use uninitialized value input_producer/input_producer/limit_epochs/epochs 今天在模型恢复的时候出现上图报错信息,最后发现是由于调用tf.train.slice_input_producer方法产生的错误信息.它本身认为是一个tensor 修改方法: 获取batch后,在sess中先初始化即可 sess.run(tf.global_variables_initializer()) ses

  • vue如何解决空格和空行报错的问题

    目录 解决空格和空行报错问题 vue出现空格警告的原因 解决空格和空行报错问题 到build文件夹下面的webpack.base.conf.js文件. 然后打开该文件,找到图下这段代码,把他注释掉. 注释掉之后,再进行页面编写的时候,空格不规范的情况下也不会再报错了. 有的版本的webpack.base.conf.js文件会如下图一样将空格检测写一个函数里,然后再module里调用,这种情况只需注释掉调用的那一行代码即可: 如图注释这一行即可 vue出现空格警告的原因 初学vue自己新建一个vu

  • 解决Vue2跨域报错AxiosError net::ERR_FAILED、 Network Error、ERR_NETWORK

    目录 请求场景: 跨域报错信息 Vue2跨域问题报错截图 解决方法 解决方法解析: 总结 请求场景: 当前页面URL:http://127.0.0.1:8000/testcase 跳转请求页面URL:http://127.0.0.1:5000/testcase_orm 使用axios请求 时 页面提示跨域报错 跨域报错信息 Access to XMLHttpRequest at ‘http://127.0.0.1:5000/testcase_orm’ fromorigin ‘http://loc

  • 快速解决百度编译器json报错的问题

    在MyEclipse中JSON字符串的换行值是不同的,必须以'/n'换行,如果只是json验证的问题,可以把json的验证关掉试试. 点击所在的项目->Project->Proterties->MyEclipse->Validation,把JSON Validator中的Manual和Build的对号给去掉,然后apply,确定,clean缓存. 清除myeclipse缓存的方法如下 找到软件导航窗内的project下的clean,选择要清除缓存的项目,点击clean projec

  • 解决laravel 5.1报错:No supported encrypter found的办法

    本文主要介绍了关于解决laravel 5.1报错:No supported encrypter found的办法,分享出来供大家参考学习,下面来看看详细的介绍: 问题描述 在使用laravel5.1进行项目开发的时候,出现了"No supported encrypter found. The cipher and / or key length are invalid."的报错信息,导致页面无法显示. 网上的绝大多数答案都是直接执行PHP artisan key:generate即可.

随机推荐