zoukankan      html  css  js  c++  java
  • 基于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);
    }
    }



  • 相关阅读:
    最大流问题
    最短路-Floyd算法和Dijkstra算法
    最小生成树-Prim算法
    最小生成树-Kruskal算法
    MP and KMP
    导出excel表格并合并单元格(不按模板导出)
    导出excel表格(按模板导出)
    datatables和template列表查询分页单元格合并
    datatables的使用
    js对象的使用
  • 原文地址:https://www.cnblogs.com/xiqoqu/p/10294529.html
Copyright © 2011-2022 走看看