Bagikan melalui


Mengelola Konkurensi dengan DependentTransaction

Objek Transaction dibuat menggunakan metode DependentClone. Satu-satunya tujuannya adalah untuk menjamin bahwa transaksi tidak dapat diterapkan saat beberapa potongan kode lainnya (misalnya, utas pekerja) masih melakukan pekerjaan pada transaksi. Ketika pekerjaan yang dilakukan dalam transaksi yang diklon selesai dan siap untuk diterapkan, ini dapat memberi tahu pembuat transaksi menggunakan metode Complete. Dengan demikian, Anda dapat menjaga konsistensi dan kebenaran data.

Kelas DependentTransaction juga dapat digunakan untuk mengelola konkurensi antara tugas-tugas asinkron. Dalam skenario ini, induk dapat terus menjalankan kode apa pun sementara klon dependen mengerjakan tugasnya sendiri. Dengan kata lain, eksekusi induk tidak diblokir sampai dependen selesai.

Membuat Klon Dependen

Untuk membuat transaksi dependen, panggil metode DependentClone dan teruskan enumerasi DependentCloneOption sebagai parameter. Parameter ini mendefinisikan perilaku transaksi jika Commit dipanggil pada transaksi induk sebelum klon dependen menunjukkan bahwa klon siap untuk penerapan transaksi (dengan memanggil metode Complete). Nilai berikut ini valid untuk parameter ini:

  • BlockCommitUntilComplete membuat transaksi dependen yang memblokir proses penerapan dari transaksi induk hingga waktu transaksi induk habis, atau hingga Complete dipanggil pada semua dependen, yang menunjukkan penyelesaiannya. Ini berguna ketika klien tidak ingin transaksi induk diterapkan sampai transaksi dependen selesai. Jika induk menyelesaikan pekerjaannya lebih awal dari transaksi dependen dan memanggil Commit pada transaksi, proses penerapan diblokir dalam keadaan di mana pekerjaan tambahan dapat dilakukan pada transaksi dan pendaftaran baru dapat dibuat, sampai semua dependen memanggil Complete. Segera setelah mereka semua menyelesaikan pekerjaan mereka dan memanggil Complete, proses penerapan untuk transaksi dimulai.

  • RollbackIfNotComplete,di sisi lain, membuat transaksi dependen yang secara otomatis dibatalkan jika Commit dipanggil pada transaksi induk sebelum Complete dipanggil. Dalam kasus ini, semua pekerjaan yang dilakukan dalam transaksi dependen tetap utuh dalam satu masa berlaku transaksi, dan tidak ada yang memiliki kesempatan untuk menerapkan sebagian dari transaksi itu saja.

Metode Complete harus dipanggil sekali saja ketika aplikasi Anda menyelesaikan pekerjaannya pada transaksi dependen; jika tidak, InvalidOperationException ditampilkan. Setelah panggilan ini diminta, Anda tidak boleh mencoba pekerjaan tambahan apa pun pada transaksi, jika tidak, maka pengecualian akan ditampilkan.

Contoh kode berikut menunjukkan cara membuat transaksi dependen untuk mengelola dua tugas konkuren dengan mengklon transaksi dependen dan meneruskannya ke utas pekerja.

public class WorkerThread  
{  
    public void DoWork(DependentTransaction dependentTransaction)  
    {  
        Thread thread = new Thread(ThreadMethod);  
        thread.Start(dependentTransaction);
    }  
  
    public void ThreadMethod(object transaction)
    {
        DependentTransaction dependentTransaction = transaction as DependentTransaction;  
        Debug.Assert(dependentTransaction != null);
        try  
        {  
            using(TransactionScope ts = new TransactionScope(dependentTransaction))  
            {  
                /* Perform transactional work here */
                ts.Complete();  
            }  
        }  
        finally  
        {  
            dependentTransaction.Complete();
             dependentTransaction.Dispose();
        }  
    }  
  
//Client code
using(TransactionScope scope = new TransactionScope())  
{  
    Transaction currentTransaction = Transaction.Current;  
    DependentTransaction dependentTransaction;
    dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);  
    WorkerThread workerThread = new WorkerThread();  
    workerThread.DoWork(dependentTransaction);  
    /* Do some transactional work here, then: */  
    scope.Complete();  
}  

Kode klien membuat cakupan transaksional yang juga mengatur transaksi ambient. Anda tidak boleh meneruskan transaksi ambient ke utas pekerja. Sebagai gantinya, Anda harus mengklon transaksi (ambient) saat ini dengan memanggil metode DependentClone pada transaksi saat ini, lalu meneruskan dependen ke utas pekerja.

Metode ThreadMethod dijalankan pada utas baru. Klien memulai utas baru, meneruskan transaksi dependen sebagai parameter ThreadMethod.

Karena transaksi dependen dibuat dengan BlockCommitUntilComplete, sudah pasti transaksi tidak dapat diterapkan sampai semua pekerjaan transaksional yang dilakukan pada utas kedua selesai dan Complete dipanggil pada transaksi dependen. Ini berarti bahwa jika cakupan klien berakhir (ketika mencoba membuang objek transaksi di akhir pernyataan using) sebelum utas baru memanggil Complete pada transaksi dependen, kode klien memblokir sampai Complete dipanggil di dependen. Kemudian transaksi dapat selesai melakukan penerapan atau membatalkan.

Masalah Konkurensi

Ada beberapa masalah konkurensi tambahan yang perlu Anda ketahui saat menggunakan kelas DependentTransaction:

  • Jika utas pekerja menggulung balik transaksi tetapi induknya mencoba untuk menerapkannya, TransactionAbortedException akan ditampilkan.

  • Anda harus membuat klon dependen baru untuk setiap utas pekerja dalam transaksi. Jangan meneruskan klon dependen yang sama ke beberapa utas, karena hanya satu dari mereka yang dapat memanggil Complete di dependen.

  • Jika utas pekerja memunculkan utas pekerja baru, pastikan untuk membuat klon dependen dari klon dependen dan meneruskannya ke utas baru.

Lihat juga