0

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

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

现在启动了 10 个并行加载进程,所有进程都具有不同的提要名称。连接是通过 Java 进行的,它们都在运行自动提交打开的语句。

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

我的陈述有什么问题?

4

1 回答 1

0

在多线程环境下,2 个线程可以看到相同的 batch_id 值,因为 select 语句发生在 insert 之前。例如,想象这个处理按顺序发生:

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.使用Prepared Statements中的方法:

 PreparedStatement ps = connection.prepareStatement("INSERT INTO audit VALUES (?, 'feedname')");
 ps.setInt(1, getNextBatchId());
 ps.execute();
于 2013-09-16T09:23:05.560 回答