利用Redis实现流水号生成

文章首发于:clawhub.club


最近有个需求,涉及到生成特定流水号:编码+14位时间YYYYMMDDHH24MMSS+6位流水号(定长),序号从000001开始,增量步长为1。
因为系统为集群部署,所以需要中间件来做后6位的增量计数。
redis的INCR命令正好合适:INCR 命令将 key 中储存的数字值增一,如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。

因为系统使用的是jedis 2.9.0 所以封装了两个简单的方法:
接口:

 /**
     * 对某个键的值自增
     * 内部键对应的值自增与键的过期时间设置非原子性,
     * 假设多线程,同时执行自增操作,计数没有问题,
     * 过期时间在此键没有调用时开始生校。
     *
     * @param key          键
     * @param cacheSeconds 超时时间,0为不超时
     * @return 值
     */
    long getAndIncrement(String key, int cacheSeconds);

单机版:

    @Override
    public long getAndIncrement(String key, int cacheSeconds) {
        long result = 0;
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            result = jedis.incr(key);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            LOGGER.error("set " + key + " = " + result);
        } finally {
            // 返还到连接池
            IOUtils.close(jedis);
        }
        return result;
    }

集群版:

    @Override
    public long getAndIncrement(String key, int cacheSeconds) {
        long result = 0;
        try {
            result = jedisCluster.incr(key);
            if (cacheSeconds != 0) {
                jedisCluster.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            LOGGER.error("set " + key + " = " + result);
        }
        return result;
    }

代码中涉及到原子性问题,但是因为正好符合我的需求,所以就不成问题。
最终流水号生成方案:

    /**
     * 流水号生成规则
     * 

* * @return the transaction id */ private String getTransactionID() { String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); String key = "xxx:xxxx:" + time; //数字补0,redis自增,两秒超时 return REQUEST + time + String.format("%06d", getAndIncrement(key, 2) + 1); }

你可能感兴趣的:(利用Redis实现流水号生成)