2011-03-15 10 views
5

एक पिछले लेनदेन में वापस रोलिंग विफलता के मामले में लेनदेन और में चेक बाधा जोड़ने का कोई तरीका है (पूरे लेनदेन को वापस करने की बजाय) ?असफल तालिका में विफलता पर रोलबैक लेनदेन ... कंसस्ट्रेंट

मेरे मामले में, जब एक वैकल्पिक तालिका ... कंसस्ट्रेंट कमांड जोड़ें विफल रहता है, तो लेनदेन को वापस सहेजने के लिए वापस नहीं किया जा सकता है (ऐसा करने का प्रयास अमान्यऑपरेशन अपवाद को फेंकता है)।

अवलोकन प्रदर्शित करने के लिए महत्वपूर्ण बिंदु:

SqlTransaction transaction = connection.BeginTransaction(); 

// ... execute SQL commands on the transaction ... 

// Create savepoint 
transaction.Save("mySavepoint"); 

try 
{ 
    // This will fail... 
    SqlCommand boom = new SqlCommand(
     "ALTER TABLE table WITH CHECK ADD CONSTRAINT ...", 
     connection, 
     transaction); 

    boom.ExecuteNonQuery(); 
} 
catch 
{ 
    // ...and should be rolled back to the savepoint, but can't. 
    try 
    { 
     transaction.Rollback("mySavepoint"); 
    } 
    catch (InvalidOperationException) 
    { 
     // Instead, an InvalidOperationException is thrown. 
     // The transaction is unusable and can only be rolled back entirely. 
     transaction.Rollback(); 
    } 
} 

और यहाँ रेडी-टू-चलाने डेमो कोड (यदि आप एक datase नामित "परीक्षण" की जरूरत है) का परीक्षण करने के लिए:

public class Demo 
{ 
    private const string _connectionString = "Data Source=(local);Integrated security=true;Initial Catalog=test;"; 
    private const string _savepoint = "save"; 
    private static readonly string _tableName = DateTime.Now.ToString("hhmmss"); 
    private static readonly string _constraintName = "CK" + DateTime.Now.ToString("hhmmss"); 

    private static readonly string _createTable = "CREATE TABLE [dbo].[" + _tableName + "] ([one] [int] NULL,[two] [int] NULL) ON [PRIMARY]"; 
    private static readonly string _insert1 = "INSERT INTO [" + _tableName + "] VALUES (1,1)"; 
    private static readonly string _addConstraint = "ALTER TABLE [dbo].[" + _tableName + "] WITH CHECK ADD CONSTRAINT [" + _constraintName + "] CHECK (([one]>(1)))"; 
    private static readonly string _insert2 = "INSERT INTO [" + _tableName + "] VALUES (2,2)"; 


    public static void Main(string[] args) 
    { 
     // Example code! Please ignore missing using statements. 

     SqlConnection connection = new SqlConnection(_connectionString); 
     connection.Open(); 

     SqlTransaction transaction = connection.BeginTransaction(); 

     SqlCommand createTable = new SqlCommand(_createTable, connection, transaction); 
     createTable.ExecuteNonQuery(); 

     // Create savepoint 
     transaction.Save(_savepoint); 

     SqlCommand insert1 = new SqlCommand(_insert1, connection, transaction); 
     insert1.ExecuteNonQuery(); 

     try 
     { 
      // This will fail... 
      SqlCommand boom = new SqlCommand(_addConstraint, connection, transaction); 
      boom.ExecuteNonQuery(); 
     } 
     catch 
     { 
      // ...and should be rolled back to the savepoint, but can't 
      transaction.Rollback(_savepoint); 
     } 

     SqlCommand insert2 = new SqlCommand(_insert2, connection, transaction); 
     insert2.ExecuteNonQuery(); 

     transaction.Commit(); 
     connection.Close(); 
    } 
} 
+0

जब मैं पूरी तरह से टीएसक्यूएल में कोशिश करता हूं तो मुझे त्रुटि मिलती है "वर्तमान लेनदेन को प्रतिबद्ध नहीं किया जा सकता है और इसे एक सेवपॉइंट पर वापस नहीं लाया जा सकता है। पूरे लेनदेन को वापस रोल करें।" - बस बर्बाद लेनदेन पर पढ़ना। –

+0

कोई दस्तावेज नहीं मिला जो स्पष्ट रूप से बताता है कि कौन सी त्रुटियां लेनदेन को समाप्त कर रही हैं (या असामान्य प्रदान की जाती है) लेकिन यह त्रुटि स्पष्ट रूप से उनमें से एक प्रतीत होती है! –

+0

वास्तव में, उस विषय पर विशिष्ट दस्तावेज की कमी लगभग कष्टप्रद है। – nodots

उत्तर

0

मैं डॉन ' टी लगता है कि आप स्क्रिप्ट में और सी # में बचत बिंदु उपयोग को जोड़ सकते हैं।

BEGIN TRANSACTION 

INSERT INTO Foos (Fooname) 
VALUES ('Bar1') 

SAVE TRANSACTION MySavePoint; 

INSERT INTO Foos (FooName) 
VALUES ('Bar2') 

ROLLBACK TRANSACTION MySavePoint 

COMMIT TRANSACTION 

यह एसक्यूएल में काम करेंगे, और निम्न कोड के साथ काम करेंगे:

using (SqlConnection conn = new SqlConnection("connectionString")) 
{ 
    conn.Open(); 

    using (SqlTransaction trans = conn.BeginTransaction()) 
    using (SqlCommand comm = new SqlCommand("The Above SQL", conn, trans)) 
    { 
     comm.ExecuteNonQuery(); 
     trans.Commit(); 
    } 
} 

यह आप trans.Rollback("MySavePoint"); करने का प्रयास करते असफल हो जायेगी क्योंकि trans वस्तु नियंत्रण में नहीं है मैं निम्नलिखित एसक्यूएल प्रदर्शन बचत बिंदु का - यह इसके बारे में नहीं जानता है।

आप दो स्वतंत्र आवेषण में एसक्यूएल बाहर विभाजित है और निम्नलिखित कोड का उपयोग करते हैं:

using (SqlConnection conn = new SqlConnection("connectionString")) 
     { 
      conn.Open(); 

      using (SqlTransaction trans = conn.BeginTransaction()) 
      using (SqlCommand comm1 = new SqlCommand("INSERT INTO Foos(fooName) VALUES('Bar1')", conn, trans)) 
      using (SqlCommand comm2 = new SqlCommand("INSERT INTO Foos(fooName) VALUES('Bar2')", conn, trans)) 
      { 
       comm1.ExecuteNonQuery(); 
       trans.Save("MySavePoint"); 
       comm2.ExecuteNonQuery(); 
       trans.Rollback("MySavePoint"); 
       trans.Commit(); 
      } 
     } 

यह आपकी अपेक्षा के अनुरूप काम करेंगे।

बस एक नोट, IDisposable लागू करने वाली वस्तुओं का हमेशा निपटान करें - अधिमानतः using कथन में।

अतिरिक्त पठन:

http://www.davidhayden.com/blog/dave/archive/2005/10/15/2517.aspx

अद्यतन: थोड़ी देर अपने नमूना कोड का उपयोग कर के लिए इस के साथ faffing के बाद, यह की तरह एसक्यूएल से आ रही त्रुटि के कारण लग रहा है, लेन-देन वापस लुढ़का जा रहा है और अनुपयोगी हो जाता है। जैसा कि एक और उत्तर में कहा गया है, ऐसा लगता है कि एसक्यूएल के साथ संयोजन के रूप में, कुछ त्रुटियों के कारण बचत बिंदुओं के बावजूद लेनदेन को मजबूती से वापस ले जाया जा रहा है। इसके लिए एकमात्र सहारा डेटाबेस के खिलाफ चलने वाले आदेशों को पुन: क्रमबद्ध करना है और सेवपॉइंट्स पर भरोसा नहीं करना है, या कम से कम उस कार्यवाही पर भरोसा नहीं करना चाहिए।

+0

क्षमा करें, मुझे नहीं पता कि savepoint विचार ACID क्यों तोड़ देगा। यह वास्तव में एक लेनदेन तंत्र है, http://msdn.microsoft.com/en-us/library/ms188378.aspx – nodots

+0

@nodots देखें, मैं देखता हूं, मैं रोलबैक के कारण अज्ञात त्रुटि के परिप्रेक्ष्य से आ रहा था, न कि एक गैर-महत्वपूर्ण कार्रवाई विफल होने या आवश्यकता नहीं होने के कारण सशर्त रूप से चुने गए रोलबैक। मैं अभी भी इस विचार से खड़ा हूं कि पूर्व-डिज़ाइन की स्थितियों के बाहर होने वाली विफलताओं को पूरे लेनदेन में विफल होना चाहिए - मैं उन बचत-बिंदुओं को उन कार्यों को चलाने का मौका मानता हूं जो लेनदेन को प्रभावित नहीं करते हैं। –

+0

@ एडम: मैंने मूल पोस्ट को स्पष्ट किया। कोई अंतराल नहीं हो रहा है। समस्या यह है कि savepoint तंत्र __basically__ काम करता है, लेकिन हमेशा नहीं (एक असफल वैकल्पिक तालिका ... कंसस्ट्रेंट स्टेटमेंट जोड़ें लेनदेन को अनुपयोगी प्रस्तुत करता है)। इसके अलावा, मुझे कोई दस्तावेज नहीं मिला जो किस तरह की त्रुटियों को एक सेवपॉइंट पर वापस लाया जा सकता है और जो नहीं कर सकता। – nodots

1

जब मैं टीएसक्यूएल में कोशिश करता हूं तो मुझे वही व्यवहार मिलता है।

BEGIN TRAN 

CREATE TABLE foo (col int) 

INSERT INTO foo values (1) 

SAVE TRANSACTION ProcedureSave; 

BEGIN TRY 
ALTER TABLE foo WITH CHECK ADD CONSTRAINT ck CHECK (col= 2) 
END TRY 
BEGIN CATCH 
    SELECT XACT_STATE() AS XACT_STATE 
    /*Returns -1, transaction is uncommittable. Next line will fail*/ 

    ROLLBACK TRANSACTION ProcedureSave 
    /*Msg 3931, Level 16, State 1: The current transaction cannot be committed and 
    cannot be rolled back to a savepoint. Roll back the entire transaction.*/ 
END CATCH 

GO 

SELECT @@TRANCOUNT AS [@@TRANCOUNT] /*Zero the transaction was rolled back*/ 

मैं डॉक्स जो यह बताता है जो त्रुटियों लेन-देन करने के लिए नेतृत्व करेंगे में कोई जानकारी नहीं मिली इस तरह से बर्बाद हो रहा। मुझे लगता है कि this connect item comment से ऐसा कोई दस्तावेज मौजूद नहीं है।

उत्तर है, त्रुटि प्रबंधन केस-बाय-केस है। यह न केवल सर्वर पर निर्भर करता है, बल्कि त्रुटि प्रकार और संदर्भ पर भी निर्भर करता है। दुर्भाग्यवश, त्रुटि त्रुटियों की कोई प्रकाशित सूची विभिन्न त्रुटियों के लिए व्यवहार नहीं है। सामान्य में, केवल सेवा त्रुटियों को कनेक्शन को मारना चाहिए और अत्यधिक शट डाउन सर्वर होना चाहिए। लेकिन जब कथन निरस्त बनाम लेनदेन निरस्त करने की बात आती है, नियमों को सारांशित करना मुश्किल है - यानी यह मामला-दर-मामला है।

+0

मैंने देखा कि नमूना कोड चलाते समय ओपी ने प्रदान किया कि लेनदेन इसका कनेक्शन खो देगा, लेकिन कनेक्शन खुला रहेगा - वास्तव में बहुत अजीब व्यवहार। –

+0

एमएस कनेक्ट आइटम को खोदने के लिए धन्यवाद, इसलिए ऐसा लगता है कि मैं संपूर्ण दस्तावेज की तलाश करना बंद कर सकता हूं। :( – nodots

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