Apa artinya sebuah SqlConnection untuk "didaftar" dalam transaksi? Apakah itu hanya berarti bahwa perintah yang saya jalankan pada koneksi akan berpartisipasi dalam transaksi?
Jika demikian, dalam keadaan apa SqlConnection secara otomatis terdaftar dalam TransactionScope ambient Transaction?
Lihat pertanyaan dalam komentar kode. Tebakan saya untuk setiap jawaban pertanyaan mengikuti setiap pertanyaan dalam tanda kurung.
Skenario 1: Membuka koneksi DI DALAM lingkup transaksi
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = ConnectToDB())
{
// Q1: Is connection automatically enlisted in transaction? (Yes?)
//
// Q2: If I open (and run commands on) a second connection now,
// with an identical connection string,
// what, if any, is the relationship of this second connection to the first?
//
// Q3: Will this second connection's automatic enlistment
// in the current transaction scope cause the transaction to be
// escalated to a distributed transaction? (Yes?)
}
Skenario 2: Menggunakan koneksi DALAM lingkup transaksi yang dibuka DI LUAR itu
//Assume no ambient transaction active now
SqlConnection new_or_existing_connection = ConnectToDB(); //or passed in as method parameter
using (TransactionScope scope = new TransactionScope())
{
// Connection was opened before transaction scope was created
// Q4: If I start executing commands on the connection now,
// will it automatically become enlisted in the current transaction scope? (No?)
//
// Q5: If not enlisted, will commands I execute on the connection now
// participate in the ambient transaction? (No?)
//
// Q6: If commands on this connection are
// not participating in the current transaction, will they be committed
// even if rollback the current transaction scope? (Yes?)
//
// If my thoughts are correct, all of the above is disturbing,
// because it would look like I'm executing commands
// in a transaction scope, when in fact I'm not at all,
// until I do the following...
//
// Now enlisting existing connection in current transaction
conn.EnlistTransaction( Transaction.Current );
//
// Q7: Does the above method explicitly enlist the pre-existing connection
// in the current ambient transaction, so that commands I
// execute on the connection now participate in the
// ambient transaction? (Yes?)
//
// Q8: If the existing connection was already enlisted in a transaction
// when I called the above method, what would happen? Might an error be thrown? (Probably?)
//
// Q9: If the existing connection was already enlisted in a transaction
// and I did NOT call the above method to enlist it, would any commands
// I execute on it participate in it's existing transaction rather than
// the current transaction scope. (Yes?)
}
Kerja bagus Triynko, jawaban Anda semua terlihat cukup akurat dan lengkap untuk saya. Beberapa hal lain yang ingin saya tunjukkan:
(1) Pendaftaran manual
Dalam kode Anda di atas, Anda (dengan benar) menunjukkan pendaftaran manual seperti ini:
Namun, juga dimungkinkan untuk melakukannya seperti ini, menggunakan Enlist = false di string koneksi.
Ada hal lain yang perlu diperhatikan di sini. Ketika conn2 dibuka, kode kumpulan koneksi tidak tahu bahwa Anda ingin mendaftarkannya nanti dalam transaksi yang sama dengan conn1, yang berarti bahwa conn2 diberikan koneksi internal yang berbeda dari conn1. Kemudian ketika conn2 terdaftar, sekarang ada 2 koneksi terdaftar sehingga transaksi harus dipromosikan ke MSDTC. Promosi ini hanya dapat dihindari dengan menggunakan pendaftaran otomatis.
(2) Sebelum .Net 4.0, saya sangat merekomendasikan pengaturan "Binding Transaksi = Eksplisit Terikat" dalam string koneksi . Masalah ini diperbaiki di .Net 4.0, membuat Explicit Unbind benar-benar tidak perlu.
(3) Menggulung
CommittableTransaction
pengaturan dan pengaturan Anda sendiriTransaction.Current
pada dasarnya sama dengan apa yangTransactionScope
dilakukan. Ini jarang benar-benar bermanfaat, hanya FYI.(4)
Transaction.Current
bersifat statis. Ini berarti bahwaTransaction.Current
hanya diatur pada utas yang menciptakanTransactionScope
. Jadi beberapa utas yang menjalankan hal yang samaTransactionScope
(mungkin menggunakanTask
) tidak mungkin.sumber
Satu situasi aneh lain yang telah kita lihat adalah bahwa jika Anda membangunnya
EntityConnectionStringBuilder
akan berantakan denganTransactionScope.Current
dan (kami pikir) mendaftar dalam transaksi. Kami telah mengamati ini di debugger, di manaTransactionScope.Current
'scurrent.TransactionInformation.internalTransaction
menunjukkanenlistmentCount == 1
sebelum membangun, danenlistmentCount == 2
sesudahnya.Untuk menghindari ini, buatlah di dalam
using (new TransactionScope(TransactionScopeOption.Suppress))
dan mungkin di luar ruang lingkup operasi Anda (kami membangunnya setiap kali kami membutuhkan koneksi).
sumber