ธุรกรรมใน. net


144

แนวทางปฏิบัติที่ดีที่สุดในการทำธุรกรรมใน C # .Net 2.0 คืออะไร คลาสใดบ้างที่ควรใช้ อะไรคือข้อผิดพลาดที่ต้องระวัง ฯลฯ สิ่งที่กระทำและย้อนกลับ ฉันเพิ่งเริ่มโครงการที่ฉันอาจต้องทำธุรกรรมบางอย่างในขณะที่แทรกข้อมูลลงในฐานข้อมูล การตอบสนองหรือลิงค์ใด ๆ สำหรับสิ่งพื้นฐานแม้กระทั่งเกี่ยวกับการทำธุรกรรมยินดีต้อนรับ


นี่คือตัวอย่างที่ดีของการทำธุรกรรมใน. NETบน codeproject เพื่อใช้เป็นการเริ่มต้น
ผู้ขาย Mitchel

คำตอบ:


271

ธุรกรรมมี 2 ประเภทหลักคือ ธุรกรรมการเชื่อมต่อและธุรกรรมโดยรอบ ธุรกรรมการเชื่อมต่อ (เช่น SqlTransaction) เชื่อมโยงโดยตรงกับการเชื่อมต่อฐานข้อมูล (เช่น SqlConnection) ซึ่งหมายความว่าคุณจะต้องผ่านการเชื่อมต่อ - ตกลงในบางกรณี แต่ไม่อนุญาต "สร้าง / ใช้ / ปล่อย" การใช้งานและไม่อนุญาตให้ทำงานข้ามฐานข้อมูล ตัวอย่าง (จัดรูปแบบสำหรับพื้นที่):

using (IDbTransaction tran = conn.BeginTransaction()) {
    try {
        // your code
        tran.Commit();
    }  catch {
        tran.Rollback();
        throw;
    }
}

ไม่ยุ่งเกินไป แต่ จำกัด เฉพาะการเชื่อมต่อของเรา "conn" ถ้าเราต้องการเรียกใช้วิธีการต่าง ๆ ตอนนี้เราต้องผ่าน "conn" รอบ ๆ

ทางเลือกคือธุรกรรมโดยรอบ ใหม่ใน. NET 2.0 วัตถุTransactionScope (System.Transactions.dll) อนุญาตการใช้งานในช่วงของการดำเนินงาน (ผู้ให้บริการที่เหมาะสมจะเข้าร่วมโดยอัตโนมัติในธุรกรรมโดยรอบ) สิ่งนี้ทำให้ง่ายต่อการปรับย้อนหลังให้เป็นรหัสที่มีอยู่ (ไม่ใช่การทำธุรกรรม) และพูดคุยกับผู้ให้บริการหลายราย (แม้ว่า DTC จะมีส่วนร่วมหากคุณพูดคุยมากกว่าหนึ่ง)

ตัวอย่างเช่น:

using(TransactionScope tran = new TransactionScope()) {
    CallAMethodThatDoesSomeWork();
    CallAMethodThatDoesSomeMoreWork();
    tran.Complete();
}

โปรดทราบที่นี่ว่าทั้งสองวิธีสามารถจัดการการเชื่อมต่อของตนเอง (เปิด / ใช้ / ปิด / กำจัด) แต่พวกเขาจะกลายเป็นส่วนหนึ่งของการทำธุรกรรมโดยรอบโดยไม่ต้องให้เราผ่านสิ่งใด ๆ

หากรหัสของคุณมีข้อผิดพลาด Dispose () จะถูกเรียกโดยไม่มี Complete () ดังนั้นจึงจะถูกย้อนกลับ รองรับการซ้อนซ้อนที่คาดไว้ถึงแม้ว่าคุณจะไม่สามารถย้อนกลับธุรกรรมภายใน แต่ทำธุรกรรมภายนอกให้เสร็จสมบูรณ์ได้: หากใครไม่พอใจธุรกรรมจะถูกยกเลิก

ข้อดีอีกอย่างของ TransactionScope คือมันไม่ได้เชื่อมโยงกับฐานข้อมูลเท่านั้น ผู้ให้บริการที่รับรู้ถึงธุรกรรมสามารถใช้งานได้ ตัวอย่างเช่น WCF หรือมีบางรุ่นของวัตถุที่เข้ากันได้กับ TransactionScope (เช่นคลาส. NET ที่มีความสามารถในการย้อนกลับ - อาจจะง่ายกว่าของที่ระลึกถึงแม้ว่าฉันไม่เคยใช้วิธีการนี้ด้วยตนเอง)

สรุปวัตถุที่มีประโยชน์มาก ๆ

คำเตือนบางอย่าง:

  • บน SQL Server 2000, TransactionScope จะไปที่ DTC ทันที สิ่งนี้ได้รับการแก้ไขใน SQL Server 2005 และสูงกว่ามันสามารถใช้ LTM (ค่าใช้จ่ายน้อยกว่ามาก) จนกว่าคุณจะพูดคุยกับแหล่งที่มา 2 แห่ง ฯลฯ เมื่อยกระดับเป็น DTC
  • มีความผิดพลาดซึ่งหมายความว่าคุณอาจต้องปรับแต่งสตริงการเชื่อมต่อของคุณ

CSLA .NET 2.0 รองรับวัตถุ TransactionScope!
Binoj Antony

ปัญหานี่คือเมื่อคุณมีธุรกรรมในวิธีแรกและวิธีนี้ (encapsulation) ไม่ทราบว่าจะถูกเรียกจากธุรกรรมหลักหรือไม่
Eduardo Molteni

1
@Eduardo - นั่นไม่ใช่ปัญหาเมื่อใช้ TransactionScope ทำให้มันน่าสนใจมาก การทำธุรกรรมดังกล่าวซ้อนและมีเพียงกระทำนอกสุด
Marc Gravell

ฉันหวังว่าคุณยังคงฟัง คุณบอกว่ามี "บางโมเดลวัตถุที่เข้ากันได้กับ TransactionScope" คุณช่วยชี้ฉันไปที่บางคนได้ไหม ขอบคุณ.
majkinetor

1
Marc อีกคำอธิบายที่ยอดเยี่ยมอีกข้อหนึ่ง เมื่อคุณพูดว่า 'รองรับการซ้อนที่คาดไว้' สำหรับบล็อกธุรกรรมที่กำหนดภายในเมธอด (CallAMethodThatDoesSomeWork () เป็นต้น) เอง? หรือด้วยสโคปที่กำหนดไว้ภายนอกไม่จำเป็นต้องใช้หรือ
Phil Cooper

11
protected void Button1_Click(object sender, EventArgs e)
   {


       using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True"))
       {
           connection1.Open();

           // Start a local transaction.
           SqlTransaction sqlTran = connection1.BeginTransaction();

           // Enlist a command in the current transaction.
           SqlCommand command = connection1.CreateCommand();
           command.Transaction = sqlTran;

           try
           {
               // Execute two separate commands.
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('a','b','c')";
               command.ExecuteNonQuery();
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('x','y','z')";
               command.ExecuteNonQuery();

               // Commit the transaction.
               sqlTran.Commit();
               Label3.Text = "Both records were written to database.";
           }
           catch (Exception ex)
           {
               // Handle the exception if the transaction fails to commit.
               Label4.Text = ex.Message;


               try
               {
                   // Attempt to roll back the transaction.
                   sqlTran.Rollback();
               }
               catch (Exception exRollback)
               {
                   // Throws an InvalidOperationException if the connection 
                   // is closed or the transaction has already been rolled 
                   // back on the server.
                   Label5.Text = exRollback.Message;

               }
           }
       }


   }

4

นอกจากนี้คุณยังสามารถรวมธุรกรรมเข้าไปในขั้นตอนการจัดเก็บของตัวเองและจัดการด้วยวิธีนั้นแทนการทำธุรกรรมใน C # เอง


1

หากคุณต้องการเพียงแค่สิ่งที่เกี่ยวข้องกับฐานข้อมูลบางส่วนหรือผู้ทำแผนที่ (เช่น NHibernate) สนับสนุนการทำธุรกรรมออกจากกล่องตามค่าเริ่มต้น


0

มันยังขึ้นอยู่กับสิ่งที่คุณต้องการ สำหรับธุรกรรม SQL พื้นฐานคุณสามารถลองทำธุรกรรม TSQL โดยใช้ BEGIN TRANS และ COMMIT TRANS ในรหัสของคุณ นั่นเป็นวิธีที่ง่ายที่สุด แต่มีความซับซ้อนและคุณต้องระมัดระวังในการส่งมอบอย่างถูกต้อง (และย้อนกลับ)

ฉันจะใช้สิ่งที่ชอบ

SQLTransaction trans = null;
using(trans = new SqlTransaction)
{
    ...
    Do SQL stuff here passing my trans into my various SQL executers
    ...
    trans.Commit  // May not be quite right
}

ความล้มเหลวใด ๆ ที่จะปรากฏขึ้นคุณทันทีusingและการทำธุรกรรมจะกระทำหรือย้อนกลับเสมอ (ขึ้นอยู่กับสิ่งที่คุณบอกให้ทำ) ปัญหาที่ใหญ่ที่สุดที่เราเผชิญคือการทำให้แน่ใจว่ามันมุ่งมั่นเสมอ การใช้ทำให้แน่ใจว่าขอบเขตของธุรกรรมมี จำกัด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.