標籤:
1. 事務的定義事務是指不可劃分,必須同時執行的工作。如果組成事務的各項工作均得到執行,則事務執行成功,若其中一項未執行,則交易回復至初始狀態,執行失敗。事務包含4個基本屬性(ACID):
- 原子性(AUTOMICITY),不可劃分為更小單元
- 一致性(CONSISTENCY),事務對外是一個整體
- 隔離性(ISOLATION),其內部對其他事務是不可見的
- 持久性(DURABILITY),當斷電恢複時,未成功提交的事務將復原至初始狀態
2. 並行存取模型和資料庫鎖定
事務的一致性和隔離性屬性依靠資料庫的鎖定機制(LOCKING MECHANISM)實現,當一個事務需要另外一個進行中的事務的資料時,資料即鎖定,直到此事務完成或是復原。事務對鎖定資料的訪問必須等待該資料的釋放,這在執行長事務時可能會影響整體效能及可擴充性。這種利用資料鎖的並發資料訪問模型被稱作是悲觀(PESSIMISTIC)模型。在樂觀(OPTIMISTIC)模型中,不使用資料鎖,而是直接讀取資料,當操作執行完成後,再讀取該資料,如果資料已經改變,則拋出異常,並使用自訂的邏輯進行處理。 3. 事務隔離等級完整的隔離在邏輯上是最優的,但在實際操作中可能會影響效能及可擴充性,例如在進行唯讀查詢時,完整的隔離就不必要了。在微調事物的隔離性時,我們可能會如下情形:
- 髒讀(DIRTY READ): 即可讀取已被另一事務改變的值,但當事務遇到問題復原時,就會出現問題。
- 不可重複讀取(NONREPEATABLE READ): 在兩次讀取另一事務中的資料值時探索資料不一致,因為兩次讀取資料之間事務已對其做了更改。
- 幻讀(PHANTON READ): 一個事務讀取另一事務要刪除的資料或是第二次讀取時讀到了另一事務剛添加的資料
LEVEL |
DIRTY READ |
NONREPEATABLE READ |
PHANTOM READ |
CONCURRENCY MODEL |
Read Uncommitted |
Yes |
Yes |
Yes |
None |
Read Committed with Locks |
No |
Yes |
Yes |
Pessimistic |
Read Committed with Snapshots |
No |
Yes |
Yes |
Optimistic |
Repeatable Read |
No |
No |
Yes |
Pessimistic |
Snapshot |
No |
No |
No |
Optimistic |
Serializable |
No |
No |
No |
Pessimistic |
在MYSQL中,只提供了4種事務隔離等級,即:
Read Uncommitted(讀取未提交內容)
在該隔離等級,所有事務都可以看到其他未提交事務的執行結果。本隔離等級很少用於實際應用,因為它的效能也不比其他層級好多少。讀取未提交的資料,也被稱之為髒讀(Dirty Read)。
Read Committed(讀取提交內容)
這是大多數資料庫系統的預設隔離等級(但不是MySQL預設的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離等級 也支援所謂的不可重複讀取(Nonrepeatable Read),因為同一事務的其他執行個體在該執行個體處理其間可能會有新的commit,所以同一select可能返回不同結果。
Repeatable Read(可重讀)
這是MySQL的預設交易隔離等級,它確保同一事務的多個執行個體在並發讀取資料時,會看到同樣的資料行。不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當使用者讀取某一範圍的資料行時,另一個事務又在該範圍插入入了新行,當使用者再讀取該範圍的資料行時,會發現有新的“幻影” 行。InnoDB和Falcon儲存引擎通過多版本並發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。
Serializable(可序列化)
這是最高的隔離等級,它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每個讀的資料行上加上共用鎖定。在這個層級,可能導致大量的逾時現象和鎖競爭。
4. 單事務和分散式交易 在ADO.NET中,一個事務一般指在一個開啟的連結中可處理的所有工作。如果需要一個事務同時包含多個連結,則需使用分散式交易。在WINDOWS中,處理分散式交易的管理工具為DTC即DISTRIBUTED TRANSACTION COORDINATOR。 5. 建立事務事務分兩種,一種是隱含交易,一種是明確交易。每一條SQL語句均以隱含交易的形式運行,也就是說即使你不顯式的建立事務,事務也是存在的,一條語句即一個事務,這種機制保證了每一條SQL語句的完整執行,即要麼成功執行,要麼復原。顯示建立事務需在程式中添加代碼。 6. 使用T-SQLT-SQL語句顯示建立事務樣本如下:
SQL: Explicit TransactionSET XACT_ABORT ONBEGIN TRY BEGIN TRANSACTION --work code here COMMIT TRANSACTIONEND TRYBEGIN CATCH ROLLBACK TRANSACTION --cleanup codeEND CATCH
注意事務的主體在TRY語句塊中,在TRY語句塊中可以使用預存程序。 7. 使用ADO.NET中的DbTransaction對象顯示建立事務範例程式碼如下:static void Main() { ConnectionStringSettings cnSetting = ConfigurationManager.ConnectionStrings["TestApp.Properties.Settings.toucaiConnectionString"]; using (MySqlConnection cn = new MySqlConnection()) { cn.ConnectionString = cnSetting.ConnectionString; cn.Open(); using (MySqlTransaction tran = cn.BeginTransaction()) { try { //work code here using (MySqlCommand cmd = cn.CreateCommand()) { cmd.Transaction = tran; cmd.CommandText = "SELECT count(*) FROM employee"; var count = (long)cmd.ExecuteScalar(); Console.WriteLine(count.ToString()); } //if we made it this far, commit tran.Commit(); } catch (Exception xcp) { tran.Rollback(); //cleanup code Console.WriteLine(xcp.Message); } } } }在這段代碼中,首先建立了一個連結化物件(cn),然後此連結化物件使用BeginTransaction()方法建立了一個事務,TRY語句塊包含了事務的相關執行代碼並提交事務,如有異常拋出,則CATCH語句塊復原事務,當然還可做些其他工作,如在備忘程式碼中修改一些變數的值。注意,命令對象(cmd)的Transaction屬性值必須設定為連結產生的事務執行個體。此事物的作用範圍僅限於TRY語句塊(應還包括CATCH語句塊),但因為這是由一個連結建立的,所以它不能被其他連結使用。 8. 設定事務隔離等級每一個連結都可設定自己的事務隔離等級,設定事務隔離等級的方法有三種:
9. System.Transactions命名空間
System.Transactions Namespace提供了更為強大的事務支援,使用起來又更為簡易,且天然支援分散式交易。 10. 使用TransactionScope建立事務除了使用連結的BegainTransaction()方法建立事務外,還可以使用System.Transactions空間中的TransactionScope類建立事務,用此方法建立的事務被稱作是“本地輕量級事務”,提供完整的分散式交易支援,更關鍵的是,這種事務是一種隱式的事務。用前一種方法建立的事務需顯示的調用commit方法和rollback方法來提交和復原,而通過TransactionScope建立的作用範圍自動包含了一個事務,並可自動認可和復原。範例程式碼如下:using (TransactionScope ts = new TransactionScope()) { using (MySqlConnection cn = new MySqlConnection()) { cn.ConnectionString = cnSetting.ConnectionString; cn.Open(); //work code here using (MySqlCommand cmd = cn.CreateCommand()) { try { cmd.CommandType = CommandType.Text; cmd.CommandText = "UPDATE employee SET empID = ‘MY002‘ WHERE empID = ‘MY001‘"; var count = cmd.ExecuteNonQuery(); cmd.CommandText = "UPDATE employees SET empID = ‘MY002‘ WHERE empID = ‘MY001‘"; count = cmd.ExecuteNonQuery(); Console.WriteLine(count.ToString()); ts.Complete(); } catch(Exception ex) { Console.WriteLine(ex.Message); } } } }這段代碼不會對資料庫做任何操作,因為第二條SQL語句有錯誤,所以雖然第一條語句是正確的,但整個事務仍會復原,資料沒有被更改,證明了復原機制運行正常。代碼由在一個USING語句中建立一個事務範圍開始,在此範圍內,如果建立一個連結,則這個連結自動事務範圍自動將一個事務添加到此連結上,命令(COMMAND)也不用再指定其Transaction屬性,如果有錯誤拋出或是沒有找到Complete()語句,則事務進行復原。否則,在見到Complete()語句時,完成整個事務。要注意,是否執行事務中(可執行)的語句,要看代碼能不能見到Complete()語句,如果我們把ts.Complete()語句放在try-catch語句塊之外,則這個事務的第一條語句仍是有效,即事務雖遇異常拋出,但仍不會復原。Complete()語句只能執行一次,如果多次執行,會拋出異常。因為連結是在事務範圍內建立的,所以如果在此範圍內建立多個連結,就可建立分散式交易。 10. 設定事務選項使用事務範圍建立事務時,可通過設定事務選項(Transaction Options)的方法來設定事務的隔離等級和事務逾時時間長度(Transaction‘s Timeout Period)。設定方法有兩個,一個是設定TransactionOptions枚舉值,另一個是使用事務範圍的建構函式設定,TransactionOptions枚舉值的值有如下3個:Required: 如果你的系統已經有一個事務正在運行,則將事務範圍中的命令添加進行,如果沒有,則建立一個,這是預設設定。RequiresNew:總是建立一個新的事務,而不管是否有已經存在的事務正在運行。比如銀行系統中已有一個事物用來處理存取款操作,如果此時需要有一個對賬操作,則不須與存取款操作存在於一個事務中,即無論存取款操作是否成功,對賬操作將獨立運行。Suppress: 忽略事務範圍內的任何事務,用於建立一個非事務的環境,在此範圍內的Compete()操作是無效的。 11. 使用分散式交易在使用事務範圍時,ADO.NET總是先產生輕量級事務,但在某些情況下,本地輕量級也會升級為分散式交易:
When a durable resource manager is used that doesn’t implement the IPromotableSinglePhaseNotification interface, such as SQL Server 2000
When two durable resource managers are enlisted in the same transaction
When the transaction spans multiple application domains
ADO.NET學習筆記-交易處理