Estoy usando una declaración MERGE
como UPSERT
para agregar un nuevo registro o actualizar el actual. Tengo varios hilos que manejan la base de datos a través de múltiples conexiones y múltiples declaraciones (una conexión y una declaración por hilo). Estoy procesando las declaraciones 50 a la vez.¿MERGE es una declaración atómica en SQL2008?
Estaba muy sorprendido de tener una infracción duplicate key
durante mis pruebas. Esperaba que fuera imposible porque el MERGE
se realizará como una sola transacción, ¿o no?
Mi Java se parece a:
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;
}
}
La consulta es el siguiente:
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);
El error lee:
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)
...
La clave sobre la mesa es una clave PRIMARY
en el campo ID
.
¿Cómo está generando la clave principal (V.ID)? – Paolo
@Paolo 'ALTER TABLE CustomerSpend ADD CONSTRAINT [PK_CustomerSpend] PRIMARY KEY CLUSTERED (ID)'. ¿Hay una mejor manera? – OldCurmudgeon
Disculpe, quise decir el valor real de la ID que estaba pasando en la consulta. Mikael lo tiene a continuación: la transacción es atómica, pero no hay nada que impida que varios hilos intenten insertar la misma clave – Paolo