描述
需求描述
数据库中一个表的某个字段(非主键),需要实现递增的效果。
实现方式
数据库自增机制
使用数据库auto increment机制,实现自增效果。
问题:由于数据库不允许非主键的自增处理,排除此方案。
先查后写
先查询数据库,获取最大值。然后再在此基础上进行+1操作。
问题:非原子操作,可能导致脏读
Redis共享锁
数据库共享资源问题。在多线程并发处理下,对数据库进行更新操作。避免出现脏读问题,使用内存数据库Redis的INCRBY实现值递增的原子性操作,解决高并发下共享数据问题。
Redis特点:不支持异步处理,内部是串行执行每一步指令.
实施
流程图
说明
- main线程获取最新数据库字段值,并缓存。
- 启用多个线程(业务抽取线程组,实现多个元数据库的抽取过程)。
- 使用Redis的INCRBY实现增量处理。(内部需要同步抽取的数据库信息,涉及到之前提到的字段自增。)
- 异步插入同步过来的数据库信息(其中,自增字段已有Redis处理)。
伪代码
1 | //主线程缓存最新dbId |
1 | //线程并行处理 |
1 | //redis incrBy递增1 |
问题
程序处理中出现报错 “redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range”
分析
redisTemplate配置1
2
3<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory"/>
</bean>
由于使用ValueOperations的set方法为点击量设置了初始值,Key的序列化器默认采用的是JdkSerializationRedisSerializer,其将初始值变成了序列化字符串存入了Redis,而Redis执行INCRBY命令时是无法识别序列化字符串为整数的。从而导致以上错误。
措施
修改value的序列化机制,改为StringRedisSerializer。
1 | <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> |
结语
“道路漫漫,がんばって!”