非自增编号字段,避免生成重复编号(以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名); }
非自增编号字段,避免生成重复编号(以pdfNo编号为例)RedisLock/ReadLock
原文:https://www.cnblogs.com/achengmu/p/10973931.html