非自增编号字段,避免生成重复编号(以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名);
        }

  








猜你喜欢

转载自www.cnblogs.com/achengmu/p/10973931.html