Bagikan melalui


Menerapkan Transaksi Eksplisit dengan menggunakan CommitableTransaction

Kelas CommittableTransaction ini menyediakan cara eksplisit bagi aplikasi untuk menggunakan transaksi, dibandingkan dengan menggunakan kelas TransactionScope secara implisit. Ini berguna untuk aplikasi yang ingin menggunakan transaksi yang sama di beberapa panggilan fungsi atau beberapa panggilan utas. Tidak seperti kelas TransactionScope, penulis aplikasi perlu secara khusus memanggil metode Commit dan Rollback untuk menerapkan atau membatalkan transaksi.

Gambaran umum kelas CommitableTransaction

Kelas CommittableTransaction ini berasal dari kelas Transaction, oleh karena itu menyediakan semua fungsionalitas yang kelas yang disebut terakhir. Secara khusus, yang berguna adalah metode Rollback pada kelas Transaction yang juga dapat digunakan untuk memutar kembali objek CommittableTransaction.

Kelas Transaction ini mirip dengan kelas CommittableTransaction tetapi tidak menawarkan metode Commit. Hal ini memungkinkan Anda untuk meneruskan objek transaksi (atau klonnya) ke metode lain (berpotensi pada utas lain) sembari tetap mengendalikan saat transaksi dilakukan. Kode yang disebut bisa mendaftar dan memberikan suara pada transaksi, tetapi hanya pembuat objek CommittableTransaction saja yang memiliki kemampuan untuk melakukan transaksi.

Anda harus mencatat hal-hal berikut saat bekerja dengan kelas CommittableTransaction,

  • Membuat transaksi CommittableTransaction tidak mengatur transaksi sekitar. Anda harus secara khusus mengatur dan mengatur ulang transaksi sekitar, untuk memastikan bahwa manajer sumber daya beroperasi di bawah konteks transaksi yang tepat bila sesuai. Cara untuk mengatur transaksi sekitar saat ini adalah dengan mengatur properti Current statis pada objek Transaction global.

  • Objek CommittableTransaction tidak bisa digunakan kembali. Setelah objek CommittableTransaction diterapkan atau digulung balik, objek tidak dapat digunakan lagi dalam transaksi. Artinya, tidak bisa diatur sebagai konteks transaksi sekitar saat ini.

Membuat CommitableTransaction

Contoh berikut ini membuat CommittableTransaction yang baru dan menerapkannya.

//Create a committable transaction
tx = new CommittableTransaction();

SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=northwind");
SqlCommand myCommand = new SqlCommand();

//Open the SQL connection
myConnection.Open();

//Give the transaction to SQL to enlist with
myConnection.EnlistTransaction(tx);

myCommand.Connection = myConnection;

// Restore database to near it's original condition so sample will work correctly.
myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
myCommand.ExecuteNonQuery();

// Insert the first record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
myCommand.ExecuteNonQuery();

// Insert the second record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
myCommand.ExecuteNonQuery();

// Commit or rollback the transaction
while (true)
{
    Console.Write("Commit or Rollback? [C|R] ");
    ConsoleKeyInfo c = Console.ReadKey();
    Console.WriteLine();

    if ((c.KeyChar == 'C') || (c.KeyChar == 'c'))
    {
        tx.Commit();
        break;
    }
    else if ((c.KeyChar == 'R') || (c.KeyChar == 'r'))
    {
        tx.Rollback();
        break;
    }
}
myConnection.Close();
tx = null;
tx = New CommittableTransaction

Dim myConnection As New SqlConnection("server=(local)\SQLExpress;Integrated Security=SSPI;database=northwind")
Dim myCommand As New SqlCommand()

'Open the SQL connection
myConnection.Open()

'Give the transaction to SQL to enlist with
myConnection.EnlistTransaction(tx)

myCommand.Connection = myConnection

'Restore database to near it's original condition so sample will work correctly.
myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)"
myCommand.ExecuteNonQuery()

'Insert the first record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')"
myCommand.ExecuteNonQuery()

'Insert the second record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')"
myCommand.ExecuteNonQuery()

'Commit or rollback the transaction
Dim c As ConsoleKeyInfo
While (True)
    Console.Write("Commit or Rollback? [C|R] ")
    c = Console.ReadKey()
    Console.WriteLine()

    If (c.KeyChar = "C") Or (c.KeyChar = "c") Then
        tx.Commit()
        Exit While
    ElseIf ((c.KeyChar = "R") Or (c.KeyChar = "r")) Then
        tx.Rollback()
        Exit While
    End If
End While

myConnection.Close()
tx = Nothing

Membuat instans CommittableTransaction tidak secara otomatis mengatur konteks transaksi sekitar. Oleh karena itu, setiap operasi pada manajer sumber daya bukanlah bagian dari transaksi tersebut. Properti statis Current pada objek global Transaction digunakan untuk mengatur atau mengambil transaksi sekitar dan aplikasi harus mengaturnya secara manual untuk memastikan manajer sumber daya dapat berpartisipasi dalam transaksi. Ini juga merupakan praktik yang baik untuk menyimpan transaksi sekitar yang sudah lama dan memulihkannya ketika Anda selesai menggunakan objek CommittableTransaction.

Untuk melakukan transaksi, Anda perlu secara eksplisit memanggil metode Commit. Untuk menggulung balik transaksi, Anda harus memanggil metode Rollback. Penting untuk dicatat bahwa hingga CommittableTransaction telah diterapkan atau digulung balik, semua sumber daya yang terlibat dalam transaksi tersebut masih terkunci.

Objek CommittableTransaction bisa digunakan di seluruh panggilan fungsi dan utas. Namun, terserah kepada pengembang aplikasi untuk menangani pengecualian dan secara khusus memanggil metode Rollback(Exception) jika terjadi kegagalan.

Penerapan Asinkron

Kelas CommittableTransaction ini juga menyediakan mekanisme untuk melakukan transaksi secara asinkron. Penerapan transaksi dapat memakan waktu yang cukup lama, karena mungkin melibatkan beberapa akses database dan kemungkinan latensi jaringan. Saat Anda ingin menghindari kebuntuan dalam aplikasi throughput tinggi, Anda dapat menggunakan komit asinkron untuk menyelesaikan pekerjaan transaksional sesegera mungkin, dan menjalankan operasi komit sebagai tugas latar belakang. Metode BeginCommit dan EndCommit dari kelas CommittableTransaction memungkinkan Anda melakukannya.

Anda bisa memanggil BeginCommit untuk mengirimkan penahanan penerapan ke utas dari kumpulan utas. Anda juga bisa memanggil EndCommit untuk menentukan apakah transaksi telah benar-benar dilakukan. Jika transaksi gagal diterapkan karena alasan apa pun, EndCommit mengajukan pengecualian transaksi. Jika transaksi belum dilakukan ketika EndCommit dipanggil, pemanggil diblokir sampai transaksi dilakukan atau dibatalkan.

Cara termudah untuk melakukan komit asinkron adalah dengan menyediakan metode callback, untuk dipanggil saat penerapan selesai. Namun, Anda harus memanggil metode EndCommit pada objek CommittableTransaction asli yang digunakan untuk memanggil panggilan. Untuk mendapatkan objek tersebut, Anda bisa menurunkan parameter IAsyncResult dari metode panggilan balik, karena kelas CommittableTransaction mengimplementasikan kelas IAsyncResult.

Contoh berikut ini menunjukkan bagaimana komit asinkron dapat dilakukan.

public void DoTransactionalWork()  
{  
     Transaction oldAmbient = Transaction.Current;  
     CommittableTransaction committableTransaction = new CommittableTransaction();  
     Transaction.Current = committableTransaction;  
  
     try  
     {  
          /* Perform transactional work here */  
          // No errors - commit transaction asynchronously  
          committableTransaction.BeginCommit(OnCommitted,null);  
     }  
     finally  
     {  
          //Restore the ambient transaction
          Transaction.Current = oldAmbient;  
     }  
}  
void OnCommitted(IAsyncResult asyncResult)  
{  
     CommittableTransaction committableTransaction;  
     committableTransaction = asyncResult as CommittableTransaction;
     Debug.Assert(committableTransaction != null);  
     try  
     {  
          using(committableTransaction)  
          {  
               committableTransaction.EndCommit(asyncResult);  
          }  
     }  
     catch(TransactionException e)  
     {  
          //Handle the failure to commit  
     }  
}  

Lihat juga