由时间和数字组成唯一编码

该博客介绍了如何使用Spring Data Redis结合日期和自增序列生成唯一的交换券编码。通过ThreadLocal避免并发问题,并利用Redis的锁机制保证编码的原子性更新,确保在高并发场景下编码的唯一性。
摘要由CSDN通过智能技术生成

import org.springframework.data.redis.core.RedisTemplate;
@Resource
private RedisTemplate redisTemplate;
@Resource
private RedisUtil redisUtil;

//生成编码
public String getExchangeTicketCode(){
String date = df.get().format(new Date());
//序列前需要填充0补足6位
String serial = date + this.getUniquecouponCode();
return serial;
};
//为了防止并发问题 这里利用ThreadLocal来保护DateFormat对象
//当然也可以将DateFormat作为方法getSerial的局部变量,每次取都new一个
private static final ThreadLocal df = new ThreadLocal() {
protected DateFormat initialValue() {
return new SimpleDateFormat(“yyyyMMddHH”);
}
};
//获取100001以后的数
public String getUniquecouponCode() {
log.info(“UserExchangeTicketInfoServiceImpl getUniquecouponCode begin”);
String lockValue = String.valueOf(System.currentTimeMillis() + 5000);
String str=“DH”;
Boolean flag;
Integer couponCode;
while (true) {
flag = redisUtil.getlock(str + “_temp”, lockValue);
if (!flag) {
log.info(“当前有进程在获取券编码”);
} else {
if (null != redisTemplate.opsForValue().get(str)) {
couponCode = ((Integer) redisTemplate.opsForValue().get(str) + 1);
redisTemplate.opsForValue().set(str, (Integer) redisTemplate.opsForValue().get(str) + 1);
} else {
redisTemplate.opsForValue().set(str, 100001);
couponCode = 100001;
}
break;
}
}
log.info(“优惠券编码code为” + couponCode);
BaseResultResponse baseResultResponse = BaseResultResponse.success(new ArrayList<>());
redisUtil.unlock(str + “_temp”, lockValue);
return couponCode.toString();
}

public class RedisUtil {

@Autowired
private RedisTemplate redisTemplate;

public boolean getlock(String key, String value) {
    //如果key值不存在,则返回 true,且设置 value
    if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
        return true;
    }

    //获取key的值,判断是是否超时
    String curVal = (String) redisTemplate.opsForValue().get(key);
    if (StringUtils.isNotEmpty(curVal) && Long.parseLong(curVal) < System.currentTimeMillis()) {
        //获得之前的key值,同时设置当前的传入的value。这个地方可能几个线程同时过来,但是redis本身天然是单线程的,所以getAndSet方法还是会安全执行,
        //首先执行的线程,此时curVal当然和oldVal值相等,因为就是同一个值,之后该线程set了自己的value,后面的线程就取不到锁了
        String oldVal = (String) redisTemplate.opsForValue().getAndSet(key, value);
        if(StringUtils.isNotEmpty(oldVal) && oldVal.equals(curVal)) {
            return true;
        }
    }
    return false;
}

/**
 * 解锁
 * @param key
 * @param value
 */
public void unlock(String key, String value) {
    try {
        String curVal = (String) redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotEmpty(curVal) && curVal.equals(value)) {
            redisTemplate.opsForValue().getOperations().delete(key);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值