2012-03-26 12 views
13

मैं MERGE कथन का उपयोग UPSERT के रूप में या तो एक नया रिकॉर्ड जोड़ने या वर्तमान अद्यतन को अद्यतन करने के लिए कर रहा हूं। मेरे पास एकाधिक कनेक्शन और एकाधिक कथन (एक कनेक्शन और प्रति थ्रेड प्रति स्टेटमेंट) के माध्यम से डेटाबेस चलाते हुए कई धागे हैं। मैं एक समय में बयान 50 बैच कर रहा हूं।क्या 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

आप प्राथमिक कुंजी (वी.आईडी) कैसे बना रहे हैं? – Paolo

+0

@ पाओलो 'अल्टर टेबल ग्राहकस्पेन्ड कंसस्ट्रेंट जोड़ें [पीके_CustomerSpend] प्राथमिक कुंजी क्लस्टर (आईडी) '। क्या कोई बेहतर तरीका है? – OldCurmudgeon

+0

क्षमा करें, मेरा मतलब है कि आप क्वेरी में गुजर रहे आईडी के वास्तविक मूल्य का मतलब है। मिकाएल को यह नीचे मिला - लेनदेन परमाणु है, लेकिन एक ही कुंजी – 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))। –

संबंधित मुद्दे