基于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);
}
}



posted @ 2019-01-20 12:42  小屈工作室  阅读(154)  评论(0编辑  收藏  举报