在实际的业务场景中,我们会用到流水号。
之前的流水号做法是,使用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
posted on 2022-04-30 23:10  自由港  阅读(319)  评论(0编辑  收藏  举报