Я использую оператор MERGE
в качестве UPSERT
, чтобы добавить новую запись или обновить текущую.У меня есть несколько потоков, управляющих базой данных через несколько соединений и несколько операторов (одно соединение и оператор на поток).Я делаю по 50 заявлений за раз.
Я был очень удивлен, когда во время тестов получил нарушение duplicate key
.Я ожидал, что это будет невозможно, потому что MERGE
будет выполняться как одна транзакция, или это так?
Мой код Java выглядит следующим образом:
private void addBatch(Columns columns) throws SQLException {
try {
// Set parameters.
for (int i = 0; i < columns.size(); i++) {
Column c = columns.get(i);
// Column type is an `enum` with a `set` method appropriate to its type, e.g. setLong, setString etc.
c.getColumnType().set(statement, i + 1, c.getValue());
}
// Add the insert as a batch.
statement.addBatch();
// Ready to execute?
if (++batched >= MaxBatched) {
statement.executeBatch();
batched = 0;
}
} catch (SQLException e) {
log.warning("addBatch failed " + sql + " thread " + Thread.currentThread().getName(), e);
throw e;
}
}
Запрос выглядит так:
MERGE INTO CustomerSpend AS T
USING ( SELECT ? AS ID, ? AS NetValue, ? AS VoidValue ) AS V
ON T.ID = V.ID
WHEN MATCHED THEN
UPDATE SET T.ID = V.ID, T.NetValue = T.NetValue + V.NetValue, T.VoidValue = T.VoidValue + V.VoidValue
WHEN NOT MATCHED THEN
INSERT ( ID,NetValue,VoidValue ) VALUES ( V.ID, V.NetValue, V.VoidValue );
Ошибка гласит:
java.sql.BatchUpdateException: Violation of PRIMARY KEY constraint 'PK_CustomerSpend'. Cannot insert duplicate key in object 'dbo.CustomerSpend'. The duplicate key value is (498288 ).
at net.sourceforge.jtds.jdbc.JtdsStatement.executeBatch(JtdsStatement.java:944)
at x.db.Db$BatchedStatement.addBatch(Db.java:299)
...
Ключ в таблице - это ключ PRIMARY
в поле ID
.