2012-03-26 7 views
13

MERGE 문을 UPSERT으로 사용하여 새 레코드를 추가하거나 현재 레코드를 업데이트하십시오. 여러 연결 및 여러 문 (스레드 당 하나의 연결 및 문)을 통해 데이터베이스를 구동하는 여러 스레드가 있습니다. 나는 한 번에 50 문장을 배치하고있다.MERGE가 SQL2008의 원자 적 진술입니까?

테스트 도중 duplicate key 번 위반을 당해서 매우 놀랐습니다. 나는 MERGE이 단일 거래로 수행 될 것이기 때문에 불가능하다고 생각합니까? 아니면 그렇습니까?

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 열쇠 쿼리는 다음과 같습니다

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; 
    } 
} 

: 같은

내 자바 코드 보인다 ID 필드에 있습니다.

+0

어떻게 기본 키 (V.ID)를 생성합니까? – Paolo

+0

@Paolo'ALTER TABLE CustomerSpend ADD CONSTRAINT [PK_CustomerSpend] PRIMARY KEY CLUSTERED (ID)'. 더 좋은 방법이 있습니까? – OldCurmudgeon

+0

죄송합니다. 귀하가 쿼리에서 전달한 ID의 실제 값을 의미했습니다. Mikael이 아래에 있습니다. 트랜잭션은 원자 적이지만, 동일한 키를 삽입하려고 시도하는 다중 스레드를 막을 수는 없습니다. – Paolo

답변

26

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); 
+0

감사합니다! 그건 의미가 있습니다. – OldCurmudgeon

+0

"* 동시성이 높은 경우 *"의 의미는 언제 알려주시겠습니까? – Pankaj

+1

@abcdefghi [병합 명령문의 동시 실행] (http://en.wikipedia.org/wiki/Concurrency_ (computer_science)). –

관련 문제