十八、SqlServer事務

一、什麼是事務?

事務是在數據庫上按照一定的邏輯順序執行的任務序列,是恢復和控制併發的基本單位,既可以由用戶手動執行,也可以由某種數據庫程序自動執行。
 
事務究竟有什麼價值呢?
轉賬:
張三像李四轉賬一萬塊錢;
業務操作: ---存在兩個操作; 業務中,必須要保證兩個操作都成功纔行!
1、張三的賬戶----存款減去10000元
2、同時李四的賬戶----存款數量要加上10000元
張三賬戶:50000元 轉出了10000元 ====40000
李四賬戶:40000元 接受了10000元 =====500000

二、事務分類

2.1、顯式事務

用 begin transaction 明確指定事務的開始,由 commit transaction 提交事務、rollback transaction 回滾事務到事務結束。

2.2、隱式事務

通過設置 set implicit_transactions on 語句,將隱式事務模式設置爲打開。當以隱式事務模式操作時,不必使用 begin transaction 開啓事務,當一個事務結束後,這個模式會自動啓用下一個事務。只需使用 commit transaction 提交事務或 rollback transaction 回滾事務即可。

2.3、自動提交事務

SQL Server的默認模式,它將每條單獨的T-SQL語句視爲一個事務。如果成功執行,則自動提交,否則回滾。

三、事務的特性

3.1、原子性

保證任務中的所有操作都執行完畢;否則,事務會在出現錯誤時終止,並回滾之前所有操作到原始狀態。

3.2、一致性

事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態。。

3.3、持久性

保證任務中的所有操作都執行完畢;否則,事務會在出現錯誤時終止,並回滾之前所有操作到原始狀態。
持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。

3.4、隔離性

保證不同的事務相互獨立、透明地執行。

四、事務不隔離導致的問題

以上介紹完事務的四大特性(簡稱ACID),現在重點來說明下事務的隔離性,當多個線程都開啓事務操作數據庫中的數據時,數據庫系統要能進行隔離操作,以保證各個線程獲取數據的準確性,在介紹數據庫提供的各種隔離級別之前,我們先看看如果不考慮事務的隔離性,會發生的幾種問題:
更新丟失(Lost update)、髒讀(Dirty Reads)、不可重複讀(Non-repeatable Reads)

4.1、更新丟失

兩個事務都同時更新一行數據,但是第二個事務卻中途失敗退出,導致對數據的兩個修改都失效了。這是因爲系統沒有執行任何的鎖操作,因此併發事務並沒有被隔離開來。

4.2、髒讀

一個事務開始讀取了某行數據,但是另外一個事務已經更新了此數據但沒有能夠及時提交。這是相當危險的,因爲很可能所有的操作都被回滾。
當一個事務正在多次修改某個數據,而在這個事務中這多次的修改都還未提交,這時一個併發的事務來訪問該數據,就會造成兩個事務得到的數據不一致。
--用戶A向用戶B轉賬1000元,B的錢增加
update account set money=money+1000 where name='B';
--此時A通知B我給你轉錢了,A的錢減少
update account set money=money - 1000 where name='A';
 當只執行第一條SQL時,A通知B查看賬戶,B發現確實錢已到賬(此時即發生了髒讀)
   而之後無論第二條SQL是否執行,只要該事務不提交,則所有操作都將回滾,那麼當B以後再次查看賬戶時就會發現錢其實並沒有轉。

4.3、不可重複讀

不可重複讀是指在對於數據庫中的某個數據,一個事務範圍內多次查詢卻返回了不同的數據值,這是由於在查詢間隔,被另一個事務修改並提交了
(1) 虛讀:事務T1讀取某一數據後,事務T2對其做了修改,當事務T1再次讀該數據時得到與前一次不同的值。
(2) 幻讀:事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺少了第一次查詢中出現的數據(這裏並不要求兩次查詢的SQL語句相同)。
這是因爲在兩次查詢過程中有另外一個事務插入數據造成的。

五、事務的隔離級別

5.1、未提交讀取(相當於with(nolock)):第一級別

也稱未授權讀取:允許髒讀取,但不允許更新丟失。
如果一個事務已經開始寫數據,則另外一個事務則不允許同時進行寫操作,但允許其他事務讀此行數據。
該隔離級別可以通過“排他寫鎖”實現。
       缺點:會產生髒讀、不可重複讀、幻讀。

5.2、提交讀取(Oracle和SQLServer默認的):第二級別

這是大多數數據庫系統的默認隔離級別(Oracle和SQLServer默認的)。
也稱爲授權讀取:允許不可重複讀取,但不允許髒讀取。
這可以通過“瞬間共享讀鎖”和“排他寫鎖”實現。讀取數據的事務允許其他事務繼續訪問該行數據,
但是未提交的寫事務將會禁止其他事務訪問該行。
       缺點:會產生不可重複讀、幻讀。

5.3、可重複讀取(相當於(HOLDLOCK)):第三級別

MySQL的默認事務隔離級別。
  可重複讀取(Repeatable Read):禁止不可重複讀取和髒讀取,但是有時可能出現幻讀數據。
這可以通過“共享讀鎖”和“排他寫鎖”實現。讀取數據的事務將會禁止寫事務(但允許讀事務),寫
事務則禁止任何其他事務。
  缺點:會產生幻讀。

5.4、序列化(這是最高的隔離級別):第四級別

序列化(Serializable):提供嚴格的事務隔離。
它要求事務序列化執行,事務只能一個接着一個地執行,不能併發執行。
僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的數據不會被剛執行查詢
操作的事務訪問到。
  缺點:可以解決併發事務的所有問題。但是效率底下,消耗數據庫性能,一般不使用。
  隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大。
對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設爲Read Committed。它能夠避免髒讀
取,而且具有較好的併發性能。
 
儘管它會導致不可重複讀、幻讀和第二類丟失更新這些併發問題,在可能出現這類問題的個別場合,可
以由應用程序採用悲觀鎖或樂觀鎖來控制。

5.5、快照

(1)SNAPSHOT 在SNAPSHOT隔離級別下,當讀取數據時可以保證操作讀取的行是事務開始時可用的最
後提交版本。
(2)同時SNAPSHOT隔離級別也滿足前面的已提交讀,可重複讀,不幻讀;該隔離級別實用的不是共享鎖,而
是行版本控制。

5.6、已提交讀快照(READ COMMITTED SNAPSHOT)

READ COMMITTED SNAPSHOT也是基於行版本控制,但是READ COMMITTED SNAPSHOT的隔離級別是讀操作之前的最後已提交版本,而不是事務前的已提交版本,有點類似前面的READ COMMITTED能保證已提交讀,但是不能保證可重複讀,不能避免幻讀,但是又比 READ COMMITTED隔離級別多出了不需要獲取共享鎖就可以讀取數據。

六、事務隔離總結

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章