背景:
事務是數據庫管理系統的一個基本概念,事務具有四個基本特點,即ACID:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability),通過事務機制可以保證數據庫的一致性和完整性。
不過數據庫事務只能在數據庫實例的同一個會話級別進行事務控制。而分布式事務可以協調一個數據庫實例多個會話之間的操作,甚至是多個數據庫實例之間的數據庫操作,並保持事務特性。但是原則上我們不推薦使用分布式事務,因為分布式事務對資源消耗較多,執行效率較差。
然而一直以來,我們對分布式事務的代碼使用和效果都存在誤解:使用了TransactionScope就一定會開啟分布式事務嗎?
驗證:
我們做一個簡單的Demo:兩個連接字符串完全相同,ADO.NET會復用連接池中的連接,結果會如何?
using (TransactionScope ts = new TransactionScope()) { SqlConnection conn; conn = new SqlConnection("server=.;uid=tkk123;pwd=aaaaaa"); conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "select 1 as tkk"; cmd.ExecuteNonQuery(); conn.Close(); conn = new SqlConnection("server=.;uid=tkk123;pwd=aaaaaa"); conn.Open(); cmd = conn.CreateCommand(); cmd.CommandText = "select 2 as tkk"; cmd.ExecuteNonQuery(); conn.Close(); ts.Complete(); } Console.WriteLine("OK"); Console.ReadKey();
奇怪的事情發生了,並沒有看到我們的以為的分布式事務!!!
using (TransactionScope ts = new TransactionScope()) { SqlConnection conn; conn = new SqlConnection("server=.;uid=tkk123;pwd=aaaaaa"); conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "select 1 as tkk"; cmd.ExecuteNonQuery(); conn.Close(); conn = new SqlConnection("server=.;uid=tkk123;pwd=aaaaaa;"); --加了一個分號,不共享連接 conn.Open(); cmd = conn.CreateCommand(); cmd.CommandText = "select 2 as tkk"; cmd.ExecuteNonQuery(); conn.Close(); ts.Complete(); } Console.WriteLine("OK"); Console.ReadKey();
讓我們看一下分布式事務是如何協調每個數據庫連接,當前的案例我們使用的是同一個數據庫,所以雖然建立了兩個數據庫連接,但最終在數據庫層面仍然是同一事務ID。
如果我們打開的是兩個不同數據庫實例,將會看到什麼樣的結果呢? try it。。。