Java实现Redis分布式锁生成规则流水单号

该文章展示了如何在JavaSpring环境中,利用RedisTemplate实现分布式锁,以及基于日期的递增流水号生成。通过setIfAbsent方法占锁,保证并发安全,同时讨论了锁的释放和处理时间回拨的问题。
摘要由CSDN通过智能技术生成

参考
https://blog.csdn.net/w_monster/article/details/124472493
第三点具体实现中的RedisTemplate实现
效果:
在这里插入图片描述

代码实现:

package cn.hhnail.backend.controller;

import cn.hhnail.backend.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author Hhnail
 * @version 1.0
 * @description: Redis分布式锁实现特定规则递增流水号
 * @date 2023/3/4 22:05
 */
@RestController
@RequestMapping("/vapi")
public class RedisController {

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @PostMapping("/lock")
    public void lock() throws Exception {

        // 分布式锁占坑
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(
                "documentNoLock", "value",
                30, TimeUnit.SECONDS
        );
        if (lock) {
            // 加锁成功,执行业务逻辑
            // todo business
            String yyyyMMdd = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String maxDocumentNo = redisTemplate.opsForValue().get(yyyyMMdd);
            // Thread.sleep(1000);
            if (maxDocumentNo == null || "".equals(maxDocumentNo)) {
                // 默认流水号从1开始
                System.out.println(getAutoDocumentNo(1));
                // 注意服务器时间回拨问题。这个过期时间,他不是一天的秒数来倒计时。而是距离当前一天的时间点。
                // 所以比如4号设置了一天,就是5号到期,如果把当前时间提前1天改到3号,这个还是5号才过期
                redisTemplate.opsForValue().set(yyyyMMdd, "2", 1, TimeUnit.DAYS);
            } else {
                int max = Integer.parseInt(maxDocumentNo);
                System.out.println(getAutoDocumentNo(max));
                redisTemplate.opsForValue().increment(yyyyMMdd);
            }
            redisTemplate.delete("documentNoLock");   //删除key,释放锁
        } else {
            // 加锁失败,重试
            Thread.sleep(100);
            lock();
        }
    }


    private String getAutoDocumentNo(Integer maxId) {
        String yyyyMMdd = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String completedMaxId = StringUtils.leftComplete(5, "0", maxId);
        return yyyyMMdd + completedMaxId;
    }

}


package cn.hhnail.backend.util;

import cn.hhnail.backend.enums.DateTemplate;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Hhnail 字符串工具类
 */

@Slf4j
public class StringUtils {
    /**
     * 使用placeholder在左边将str补全到length长度
     * eg:leftComplete(5,"0","123") = "00123"
     *
     * @param length
     * @param placeholder
     * @param str
     * @return
     */
    public static String leftComplete(Integer length, String placeholder, Object str) {
        StringBuffer result = new StringBuffer();
        for (Integer i = 0; i < length - ("" + str).length(); i++) {
            result.append(placeholder);
        }
        result.append(str);
        return result.toString();
    }
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值