Transaksi dalam .net

144

Apa praktik terbaik untuk melakukan transaksi di C # .Net 2.0. Kelas apa yang harus digunakan? Apa jebakan yang harus diwaspadai dll. Semua hal-hal yang komit dan kembalikan. Saya baru memulai proyek di mana saya mungkin perlu melakukan beberapa transaksi saat memasukkan data ke dalam DB. Setiap tanggapan atau tautan untuk hal-hal mendasar tentang transaksi disambut.

Malik Daud Ahmad Khokhar
sumber
Berikut ini adalah contoh yang baik dari Transaksi di .NET keluar pada proyek codep untuk digunakan sebagai permulaan.
Penjual Mitchel

Jawaban:

271

Ada 2 jenis transaksi utama; transaksi koneksi dan transaksi sekitar. Transaksi koneksi (seperti SqlTransaction) terkait langsung dengan koneksi db (seperti SqlConnection), yang berarti Anda harus terus melewati koneksi - OK dalam beberapa kasus, tetapi tidak mengizinkan "buat / gunakan / lepaskan" penggunaan, dan tidak memungkinkan kerja lintas-db. Contoh (diformat untuk spasi):

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

Tidak terlalu berantakan, tetapi terbatas pada koneksi kami "samb". Jika kita ingin memanggil metode yang berbeda, kita sekarang perlu memberikan "koneksi".

Alternatifnya adalah transaksi ambient; baru di .NET 2.0, objek TransactionScope (System.Transactions.dll) memungkinkan penggunaan pada berbagai operasi (penyedia yang sesuai akan secara otomatis mendaftar dalam transaksi ambient). Ini memudahkan retro-fit ke dalam kode (non-transaksional) yang ada, dan berbicara dengan banyak penyedia (meskipun DTC akan terlibat jika Anda berbicara dengan lebih dari satu).

Sebagai contoh:

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

Perhatikan di sini bahwa kedua metode dapat menangani koneksi mereka sendiri (buka / gunakan / tutup / buang), namun mereka akan diam-diam menjadi bagian dari transaksi ambient tanpa kita harus memasukkan apa pun.

Jika kode Anda salah, Buang () akan dipanggil tanpa Lengkap (), sehingga akan dibatalkan. Sarang yang diharapkan dll didukung, meskipun Anda tidak dapat memutar kembali transaksi dalam belum menyelesaikan transaksi luar: jika ada yang tidak senang, transaksi dibatalkan.

Keuntungan lain dari TransactionScope adalah ia tidak hanya terikat pada basis data; semua penyedia yang mengetahui transaksi dapat menggunakannya. WCF, misalnya. Atau bahkan ada beberapa model objek yang kompatibel dengan TransactionScope (mis. Kelas .NET dengan kemampuan rollback - mungkin lebih mudah daripada kenang-kenangan, meskipun saya belum pernah menggunakan pendekatan ini sendiri).

Semua dalam semua, objek yang sangat, sangat bermanfaat.

Beberapa peringatan:

  • Pada SQL Server 2000, TransactionScope akan langsung menuju DTC; ini diperbaiki dalam SQL Server 2005 dan di atas, dapat menggunakan LTM (apalagi overhead) sampai Anda berbicara dengan 2 sumber dll, ketika dinaikkan ke DTC.
  • Ada kesalahan yang berarti Anda mungkin perlu mengubah string koneksi Anda
Marc Gravell
sumber
CSLA .NET 2.0 mendukung objek TransactionScope!
Binoj Antony
Masalahnya di sini adalah ketika Anda memiliki transaksi dalam metode pertama dan metode ini (enkapsulasi) tidak tahu apakah akan dipanggil dari transaksi induk atau tidak.
Eduardo Molteni
1
@Eduardo - itu tidak masalah saat menggunakan TransactionScope, membuatnya sangat menarik. Transaksi seperti itu bersarang, dan hanya yang terluar yang melakukan.
Marc Gravell
Saya harap Anda masih mendengarkan. Anda mengatakan bahwa ada "beberapa model objek yang kompatibel dengan TransactionScope". Bisakah Anda mengarahkan saya ke beberapa dari mereka? Terima kasih.
majkinetor
1
Lagi-lagi Marc, penjelasan bagus lainnya. Ketika Anda mengatakan 'sarang diharapkan didukung' adalah bahwa untuk blok transaksi didefinisikan dalam metode (CallAMethodThatDoesSomeWork () misalnya) sendiri? Atau dengan lingkup transaksi yang ditentukan di luar, tidak perlu?
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;

               }
           }
       }


   }
Ali Gholizadeh
sumber
4

Anda juga bisa membungkus transaksi menjadi prosedur tersimpan sendiri dan menanganinya seperti itu daripada melakukan transaksi di C # itu sendiri.

Charles Graham
sumber
1

jika Anda hanya memerlukannya untuk hal-hal yang berkaitan dengan db, beberapa ATAU Pemetaan (mis. NHibernate) mendukung transactinos di luar kotak per default.

Joachim Kerschbaumer
sumber
0

Itu juga tergantung pada apa yang Anda butuhkan. Untuk transaksi SQL dasar, Anda dapat mencoba melakukan transaksi TSQL dengan menggunakan BEGIN TRANS dan COMMIT TRANS dalam kode Anda. Itu adalah cara termudah tetapi memang memiliki kompleksitas dan Anda harus berhati-hati untuk melakukan dengan benar (dan kembalikan).

Saya akan menggunakan sesuatu seperti

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
}

Kegagalan akan membuat Anda keluar dari usingdan transaksi akan selalu komit atau kembalikan (tergantung pada apa yang Anda suruh lakukan). Masalah terbesar yang kami hadapi adalah memastikan itu selalu dilakukan. Penggunaan memastikan lingkup transaksi terbatas.

Brody
sumber