非自增编号字段,避免生成重复编号(以pdfNo编号为例)RedisLock/ReadLock
2024-08-22 08:01:21
非自增编号字段,避免生成重复编号(以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名);
}
最新文章
- MongoDB学习系列(1)--入门介绍
- tcl使用笔记
- C#开发ActiveX控件及指纹采集
- 不要在类的函数中使用static字段
- 不定义JQuery插件,不要说会JQuery
- Flex通信-与Java实现Socket通信实例
- selenium 启动ie 浏览器
- Java基础知识强化之集合框架笔记37:用户登录注册案例
- JavaEE:XML解析
- chrome开发工具指南(八)
- javascript入门篇(五)
- ES6-个人学习大纲
- cdh日常维护常见问题及解决方案
- Vue - Router 路由
- jquery之find,filter,has对比
- 洛谷P3121 审查(黄金)Censoring(Gold) [USACO15FEB] AC自动机
- GitHub C 和 C++ 开源库的清单(含示例代码)
- [BUG随想录] expat不兼容BUG
- 修改MySQL的时区,涉及参数time_zone
- WSAAsyncSelect模型触发不了FD_Close消息?