zoukankan      html  css  js  c++  java
  • 非自增编号字段,避免生成重复编号(以pdfNo编号为例)RedisLock/ReadLock

    非自增编号字段,避免生成重复编号(以pdfNo编号为例)

    有个场景,用户查询延误航班信息,然后生产一个编号,默认第一个编号是1000001,其后新增的编号默认自增加1。每次有人来查延误信息,如果延误信息存在,则取查询数据库pdfNo字段,查询最大的编号,然后+1后,再插入一条新的延误记录。这样会造成多人同时查询,并生成延误记录是,pdfNo的编号会重复现象。

    经过分析,俺们组长说,有2中多种解决方案,一种是分布式锁方案,一种是insert into select from方案,一种是RedisLock方案。

    本人愚笨,说下insert into select from, 和 RedisLock方案

    insert into select from:

    在入库的时候,查询下最大pdfNo,然后加一入库

    方法一:
    INSERT INTO Websites (name, country)
    SELECT app_name, country FROM apps
    WHERE id=1;
    

      

    二:
    表结构如上图
    insert into test_aaa (title, pdfno)  select "hello", max(pdfno) +1 as pdfmax from test_aaa;
    

      

    RedisLock方法

    VariableKeyLock.java
    import java.util.concurrent.locks.Lock;
    
    /**
     * 可变key锁
     *
     * @author zhangyang-b
     */
    public interface VariableKeyLock extends Lock {
    
        boolean tryLock(String key);
    
        void lock(String key);
    
        void unlock(String key);
    }
    

      

    RedisLock.java

    public class RedisLock implements VariableKeyLock {
    
        public static final String LOCK = "LOCK";
    
        @Autowired
        private RedisConnectionFactory factory;
    
        private ThreadLocal<String> localValue = new ThreadLocal<String>();
    
        /**
         * 解锁lua脚本
         */
        private static final String UNLOCK_LUA =
            "if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end";
    
        @Override
        public void lock() {
            if (!tryLock()) {
                try {
                    Thread.sleep(new Random().nextInt(10) + 1);
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                }
                lock();
            }
        }
    
        @Override
        public void lock(String key) {
            if (!tryLock(key)) {
                try {
                    Thread.sleep(new Random().nextInt(10) + 1);
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                }
                lock(key);
            }
        }
    
        @Override
        public boolean tryLock() {
            RedisConnection connection = null;
            try {
                connection = factory.getConnection();
                Jedis jedis = (Jedis)connection.getNativeConnection();
                String value = UUID.randomUUID().toString();
                localValue.set(value);
                String ret = jedis.set(LOCK, value, "NX", "PX", 10000);
                return ret != null && "OK".equals(ret);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
            return false;
        }
    
        @Override
        public boolean tryLock(String key) {
            RedisConnection connection = null;
            try {
                connection = factory.getConnection();
                Jedis jedis = (Jedis)connection.getNativeConnection();
                String value = UUID.randomUUID().toString();
                localValue.set(value);
                String ret = jedis.set(key, value, "NX", "PX", 10000);
                return ret != null && "OK".equals(ret);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
            return false;
        }
    
        @Override
        public void unlock() {
            String script = UNLOCK_LUA;
            RedisConnection connection = null;
            try {
                connection = factory.getConnection();
                Object jedis = connection.getNativeConnection();
                if (jedis instanceof Jedis) {
                    ((Jedis)jedis).eval(script, Arrays.asList(LOCK), Arrays.asList(localValue.get()));
                } else if (jedis instanceof JedisCluster) {
                    ((JedisCluster)jedis).eval(script, Arrays.asList(LOCK), Arrays.asList(localValue.get()));
                }
    
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
    
        }
    
        @Override
        public void unlock(String key) {
            String script = UNLOCK_LUA;
            RedisConnection connection = null;
            try {
                connection = factory.getConnection();
                Object jedis = connection.getNativeConnection();
                if (jedis instanceof Jedis) {
                    ((Jedis)jedis).eval(script, Arrays.asList(key), Arrays.asList(localValue.get()));
                } else if (jedis instanceof JedisCluster) {
                    ((JedisCluster)jedis).eval(script, Arrays.asList(key), Arrays.asList(localValue.get()));
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }
    
    }
    

      

    用法:
          redisLock.lock(key名);
            try{
                int maxPdfNo = 0;
                try{
                    maxPdfNo = flightDelayPdfJService.queryMaxPdfNo();
                }catch (Exception e){
                    e.printStackTrace();
                }
                if(maxPdfNo > 0){
                    return maxPdfNo + 1;
                }else{
                    return 1000001;
                }
            }finally {
                redisLock.unlock(key名);
            }
    

      








  • 相关阅读:
    深入浅出JSONP--解决ajax跨域问题
    Apache与Tomcat的区别
    项目终于接近尾声了
    交互设计[小插曲]--网站UI配色
    使用 Jasmine 进行测试驱动的 JavaScript 开发
    javascript单元测试
    MySQL查询当前数据库中所有记录不为空的表
    cannot be resolved to a type的错误
    oracle 表空数据导出dmp ,空表导出失败
    Iterable<E> Iterator<E>
  • 原文地址:https://www.cnblogs.com/achengmu/p/10973931.html
Copyright © 2011-2022 走看看