非自增編號字段,避免生成重複編號(以pdfNo編號爲例)RedisLock/ReadLock

非自增編號字段,避免生成重複編號(以pdfNo編號爲例)java

有個場景,用戶查詢延誤航班信息,而後生產一個編號,默認第一個編號是1000001,其後新增的編號默認自增長1。每次有人來查延誤信息,若是延誤信息存在,則取查詢數據庫pdfNo字段,查詢最大的編號,而後+1後,再插入一條新的延誤記錄。這樣會形成多人同時查詢,並生成延誤記錄是,pdfNo的編號會重複現象。redis

通過分析,俺們組長說,有2中多種解決方案,一種是分佈式鎖方案,一種是insert into select from方案,一種是RedisLock方案。數據庫

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

insert into select from:dom

在入庫的時候,查詢下最大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方法ide

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.javalua

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名);
        }
相關文章
相關標籤/搜索