保姆级Java项目根据年月日生成有序自增编号

技术:采用的是redis的自增生成有序编号

补零方法


    /**
     * 生成编号
     * @param type 编号开头
     * @param number 编号
     * @return
     */
    private  String getCode(String type, String number) {
        String date = DateUtil.format(new Date(), "yyyyMMdd");
        StringBuffer buffer = new StringBuffer();
        buffer.append(type)
                .append(date);
        for (int i = number.length(); i < 6; i++) {
            buffer.append("0");
        }
        buffer.append(number);
        return buffer.toString();
    }
    /**
     * 自增编号
     * @param key 编号开头
     * @return
     */
    public String getOrderCode(String key) {
        //如果值存在,直接自增返回        @第一个if
        if (RedisUtils.hasKey(key)) {
            return getCode(key, RedisUtils.incr(key).toString());
        }
        //拿不到值,说明可能到了零点,自增值失效,需要重新set 一个0进去
        //需要考虑分布式和本地并发问题,分布式通过redssion lock解决
        //本地并发可以通过lock 和 tryLock两种方案,lock是把while(true)放里面,本方案采用tryLock
        //while(true)里面两个分支,第一个分支是拿到锁,进去后需要考虑,执行成功后,临界区的线程进来所以需要先判空
        //第二个分支是拿不到锁,判断一下是否已经被拿到锁的线程set值成功,如果成功,直接返回
        boolean lock = RedisUtils.getLock(BmsConstant.CODE_LOCK_KEY + key, key, BmsConstant.INTEGER_ONE);
        try {
            while (true) {
                //拿到锁就初始化值和失效时间,没拿到锁就继续获取key的值
                if (lock) { // @第二个if
                    if (RedisUtils.hasKey(key)) {  // @第三个if
                        RedisUtils.set(key, 0, getNowToNextDayMilliseconds(), TimeUnit.MILLISECONDS);
                    }
                    return getCode(key, RedisUtils.incr(key).toString());
                } else {
                    if (RedisUtils.hasKey(key)) {// @第四个if
                        return getCode(key, RedisUtils.incr(key).toString());
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException();
        } finally {
            RedisUtils.releaseLock(BmsConstant.CODE_LOCK_KEY + key, key);
        }
    }
    /**
     * 今日剩余时间计算
     * @return
     */
    public Long getNowToNextDayMilliseconds() {
        //获取当前时间
        Calendar calendar = Calendar.getInstance();
        //当前天+1
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        //将时分秒毫秒都设为0
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        //减去当前时间获取插值
        return (calendar.getTimeInMillis() - System.currentTimeMillis());
    }
RedisUtils工具类
@UtilityClass
public class RedisUtils {

    private static final Long SUCCESS = 1L;

     /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        RedisTemplate<Object, Object> redisTemplate = SpringContextHolder.getBean(RedisTemplate.class);
        return Optional.ofNullable(redisTemplate).map(template -> template.hasKey(key)).orElse(false);
    }

    /**
     * 普通自增
     * @param key 键
     * @return 值
     */
    public Long incr(String key){
        RedisTemplate redisTemplate = SpringContextHolder.getBean(RedisTemplate.class);
        return redisTemplate.opsForValue().increment(key);
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key      键
     * @param value    值
     * @param time     时间
     * @param timeUnit 类型
     * @return true成功 false 失败
     */
    public <T> boolean set(String key, T value, long time, TimeUnit timeUnit) {
        RedisTemplate<String, T> redisTemplate = SpringContextHolder.getBean(RedisTemplate.class);
        Optional.ofNullable(redisTemplate).map(template -> {
            if (time > 0) {
                template.opsForValue().set(key, value, time, timeUnit);
            } else {
                template.opsForValue().set(key, value);
            }
            return true;
        });
        return true;
    }

    /**
     * 获取锁
     *
     * @param lockKey         锁key
     * @param value           value
     * @param expireTime:单位-秒
     * @return boolean
     */
    public boolean getLock(String lockKey, String value, int expireTime) {
        RedisTemplate<Object, Object> redisTemplate = SpringContextHolder.getBean(RedisTemplate.class);
        return Optional.ofNullable(redisTemplate)
                .map(template -> template.opsForValue().setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS))
                .orElse(false);
    }

    /**
     * 释放锁
     *
     * @param lockKey 锁key
     * @param value   value
     * @return boolean
     */
    public boolean releaseLock(String lockKey, String value) {
        RedisTemplate<Object, Object> redisTemplate = SpringContextHolder.getBean(RedisTemplate.class);
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        return Optional.ofNullable(redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value))
                .map(Convert::toLong)
                .filter(SUCCESS::equals)
                .isPresent();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值