基于Redis实现分布式锁

本文探讨了分布式锁的特性及其实现方案,包括数据库、缓存Redis和Zookeeper等不同场景的应用。并通过一个具体案例——自动生成编码,展示了如何使用Redis实现编码池的初始化、获取和清空操作,确保在多客户同时提交数据的情况下,每个人都能获得唯一的编码。

分布式锁具有的特性:

1、排他性:

  文件系统:

       数据库:主键 唯一约束 for update

    性能较差,容易出现单点故障

    锁没有失效时间,容易死锁

       缓存Redis:setnx

    实现复杂:

    存在死锁(或短时间死锁)的可能

       zookeeper:类似文件系统

               实现相对简单

     可靠性高

    性能较好

应用场景:

自动生成编码,格式为:"YYYYMMDD001"

多客户同时提交数据,数据库里出现多人存储一个编码。应实现效果,每人一个编码。

解决方案:

1、在redis里,创建一个编码池(每天凌晨1点初始化)。

2、每次项目启动,初始化redis编码池

3、编码池里没有编码,去数据库里查询当天最大编码,然后+1

 

@Component
public class CodeNumPool implements ApplicationRunner {

@Autowired
private ICodeNumRedisService codeNumRedisService;

@Autowired
private PeopleBusinessBasicInfoRepository peopleBusinessBasicInfoRepository;

/**
* @Author: qsy
* @Date: Created in 上午 11:24 2019/1/3/003
* @Description: 每天1:00重置编码池
*/
@Scheduled(cron = "0 0 1 * * ?")
public void ResetCodeNoPool() {
codeNumRedisService.deleteCodeNumPool();
codeNumRedisService.initCodeNumPool(1);
}

/**
* @Author: qsy
* @Date: Created in 下午 4:59 2019/1/3/003
* @Description: 项目一启动就初始化redis编码池
*/
@Override
public void run(ApplicationArguments args) throws Exception {
String oldCodeNo = peopleBusinessBasicInfoRepository.findNewCodeNo();
String codeNum = CodeNoUtils.getDateStr(oldCodeNo);
Integer no = StringUtil.stringToInteger(codeNum.substring(9, 13));
codeNumRedisService.deleteCodeNumPool();
codeNumRedisService.initCodeNumPool(no);
}
}

public interface ICodeNumRedisService {

/**初始化编码池*/
boolean initCodeNumPool(int no);

/**获取编码*/
String getCodeNum();

/**清空编码池*/
boolean deleteCodeNumPool();

}
@Service
public class CodeNumRedisServiceImpl implements ICodeNumRedisService {
@Autowired
private RedisTemplate<String, String> redisTemplate;


/**
* @Author: qsy
* @Date: Created in 下午 3:01 2019/1/3/003
* @Description: 初始化编码池
*/
@Override
public boolean initCodeNumPool(int no) {
Boolean res = redisTemplate.opsForValue().setIfAbsent(Constans.INIT_NUM_LOCK, Constans.INIT_NUM_LOCK);
if (res) {
ListOperations<String, String> list = redisTemplate.opsForList();
for (int i = no; i < Constans.MAX_NUM; i++) {
String codeNo = StringUtil.DecimalFormat(i, Constans.FORMAT);
list.leftPush(Constans.CODE_NUM_POOL, "P" + DateUtil.getReqDate() + codeNo);
}
redisTemplate.delete(Constans.INIT_NUM_LOCK);
}

return true;
}

/**
* @Author: qsy
* @Date: Created in 下午 3:01 2019/1/3/003
* @Description: 获取编码
*/
@Override
public String getCodeNum() {
//加锁
while (true) {
Boolean res = redisTemplate.opsForValue().setIfAbsent(Constans.NUM_LOCK, Constans.INIT_NUM_LOCK);
if (res) {
ListOperations<String, String> list = redisTemplate.opsForList();
//释放锁
String num = list.rightPop(Constans.CODE_NUM_POOL);
redisTemplate.delete(Constans.NUM_LOCK);
return num;
}
}
}

/**
* @Author: qsy
* @Date: Created in 下午 3:00 2019/1/3/003
* @Description: 清空编码池
*/
@Override
public boolean deleteCodeNumPool() {
return redisTemplate.delete(Constans.CODE_NUM_POOL);
}
}



转载于:https://www.cnblogs.com/xiqoqu/p/10294529.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值