복붙노트

[SQL] 2008 SQL에 원자 MERGE 문인가?

SQL

2008 SQL에 원자 MERGE 문인가?

나도 새 레코드를 추가하거나 현재 업데이트에 UPSERT으로 MERGE 문을 사용하고 있습니다. 나는 여러 연결과 여러 문 (스레드 당 하나 개의 연결 및 문)을 통해 데이터베이스를 구동 다중 스레드를 가지고있다. 나는 한 번에 문 (50)를 일괄 처리하고 있습니다.

나는 매우 내 시험 중에 중복 키 위반을 얻을 수 놀랐습니다. 나는 MERGE는 단일 트랜잭션으로 수행되기 때문에 그건 불가능 될 것으로 예상, 또는 무엇입니까?

내 자바 코드는 다음과 같습니다

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)
...

테이블의 키는 ID 필드에 기본 키입니다.

해결법

  1. ==============================

    1.MERGE 모든 변경이 최선을 다하고 있습니다 또는 모든 변경 사항이 롤백 어느 쪽이든 원자 의미입니다.

    MERGE 모든 변경이 최선을 다하고 있습니다 또는 모든 변경 사항이 롤백 어느 쪽이든 원자 의미입니다.

    그것은 높은 동시성의 경우에 중복 키를 방지하지 않습니다. HOLDLOCK 힌트를 추가하면 그 처리됩니다.

    MERGE INTO CustomerSpend WITH (HOLDLOCK) 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 );
    
  2. from https://stackoverflow.com/questions/9871644/is-merge-an-atomic-statement-in-sql2008 by cc-by-sa and MIT license