所以我有一个将数据加载到表中的过程。在此之前,根据目标指令(无法更改),审计记录放在如下表格中:
INSERT INTO audit VALUES (SELECT (MAX(batch_id) + 1), "feedname" from audit)
。
现在启动了10个加载的并行进程,所有进程都使用不同的feedname。连接是通过Java进行的,它们都运行自动提交ON的语句。
但是,由于batch_id主键约束,它们会相互冲突。
我的陈述有什么问题?
答案 0 :(得分:0)
对于多线程环境,2个线程可以看到相同的batch_id值,因为select语句在插入之前发生。 例如,假设此处理按顺序发生:
Thread 1:
SELECT (MAX(batch_id) + 1) # returns 1
Thread 2:
SELECT (MAX(batch_id) + 1) # returns 1 again, nothing has changed
Thread 1:
INSERT INTO audit VALUES (1, "feedname"); # because 1 was SELECTed before
Thread 2:
INSERT INTO audit VALUES (1, "feedname"); #crash!
如果您的数据库支持它,请使用序列或自动增量主键。
编辑:回应OP的评论
1.通过使用SQL语句将下一个batch_id值转换为Java变量来实现过程:
SELECT (MAX(batch_id) + 1) from audit;
2.使用同步Java方法获取下一个ID:
private synchronized int getNextBatchId() {
return nextId++;
}
3.在准备好的陈述中使用方法:
PreparedStatement ps = connection.prepareStatement("INSERT INTO audit VALUES (?, 'feedname')");
ps.setInt(1, getNextBatchId());
ps.execute();