1

我有一个名为 CUSTOMERS 的表,其中包含以下列:

CUSTOMER_ID (NUMBER)、DAY(DATE)、REGISTERED_TO(NUMBER)

表中有更多列,但这与我的问题无关,因为只有上述列一起定义为主键

在我们的应用程序中,我们对该表进行了大量插入,因此我们不使用MERGE,而是使用以下语句:

INSERT INTO CUSTOMERS  (CUSTOMER_ID , DAY, REGISTERED_TO)                      
                   SELECT ?, ?, ? 
                   FROM DUAL WHERE NOT EXISTS 
                            (SELECT NULL 
                             FROM CUSTOMERS
                             WHERE CUSTOMER_ID = ? 
                               AND DAY = ? 
                               AND REGISTERED_TO = ?
                              )";

我们使用一个PreparedStatement使用批处理功能的对象来插入通过每个客户的应用程序流收集的大量记录。

问题是有时我会收到以下错误:

ORA-00001: 违反了唯一约束 (CUSTOMERS_PK)

奇怪的是,当我使用批量插入并一一插入每条记录(通过简单地执行pstmt.execute())时,没有错误。

插入语句有问题吗?jdbc 驱动程序?我没有正确使用批处理机制吗?

这是我的插入循环的半伪代码:

  pstmt = conn.prepareStatement(statement);
  pstmt.setQueryTimeout(90);

  for each customer :
     - pstmt.setObject(1, customer id);
     - pstmt.setObject(2, current day);
     - pstmt.setObject(3, registered to);
     - pstmt.addBatch();
  end for

  pstmt.executeBatch();

它全部包含在 try/catch/finally 块中,确保在此过程结束时关闭语句和连接。

4

1 回答 1

2

我猜您正在并行使用多个线程或进程,每个线程或进程都进行插入。在这种情况下,Oracle 的事务隔离功能会阻止您进行合并的尝试,因为有时会发生以下情况:

  • 会话 A 运行您的语句,插入一行 (x,y,z)
  • 会话 B 运行相同的语句,尝试插入行 (x,y,z),获取锁并等待
  • 会话 A 提交
  • 会话 B 收到“违反唯一约束”错误

这是因为在会话 A 提交之前,会话 B 看不到新行,因此它会尝试插入相同的行。

于 2012-11-27T14:49:12.050 回答