INSERT语句中的竞争条件

时间:2013-09-16 09:07:51

标签: java sql jdbc sybase

所以我有一个将数据加载到表中的过程。在此之前,根据目标指令(无法更改),审计记录放在如下表格中:

INSERT INTO audit VALUES (SELECT (MAX(batch_id) + 1), "feedname" from audit)

现在启动了10个加载的并行进程,所有进程都使用不同的feedname。连接是通过Java进行的,它们都运行自动提交ON的语句。

但是,由于batch_id主键约束,它们会相互冲突。

我的陈述有什么问题?

1 个答案:

答案 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();