在实际的业务场景中,我们会用到流水号。
之前的流水号做法是,使用redis的全局锁。然后对数据库进行更新,数据库更新 这个也会有一些问题,比如对于同一个流水号,多个线程去更新,由于事务比较长,那么就会导致数据库被锁定。
这个可以使用redis的lua 脚本去解决。
由于redis 是单线程的处理模式,因此执行 lua 脚本的时候,是不会有并发问题的。
相关代码:
private Long getNo(String key,Integer initVal,Short step,Integer timeout){
DefaultRedisScript<Long> redisScript= new DefaultRedisScript<>();
//setex (key,timeout,val)
String script="if(redis.call('exists',KEYS[1])==0) then redis.call('setex',KEYS[1], tonumber(KEYS[4]), tonumber(KEYS[2])) else redis.call('incrby',KEYS[1],tonumber(KEYS[3])) end return tonumber(redis.call('get',KEYS[1]))";
redisScript.setScriptText(script);
List list=new ArrayList<>();
//键
list.add(key);
//初始值
list.add(initVal.toString());
//步长
list.add(step.toString());
//超时时间
list.add(timeout.toString());
redisScript.setResultType(Long.class);
Long rtn=(Long) redisTemplate.execute(redisScript,list);
return rtn;
}
这里需要注意的是,KEYS 为参数,list为参数传入,这里需要保证数据的类型和redis 的函数保持一致。
另外我们需要保证redis 的存储。
我们可以使用AOF模式
//启动AOf
appendonly yes
//每秒同步
appendfsync everysec