數據庫事務原理及並發、死鎖


1. 什么是數據庫事務
1.1 數據庫事務是指作為單個邏輯工作單元執行的一系列操作(SQL語句)。這些操作要么全部執行,要么全部不執行。
1.2 通過ACID實現數據庫事務模型
1.2.1 原子性(Atomicity):事務是數據庫的邏輯工作單位,它對數據庫的修改要么全部執行,要么全部不執行。
1.2.2 一致性(Consistemcy):事務執行前后,數據庫的狀態都滿足所有的完整性約束。
1.2.3 隔離性(Isolation):並發執行的事務是隔離的,保證多個事務互不影響。如果有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在系統中認為只有該事務在使用系統。這種屬性有時稱為串行化,為了防止事務操作間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。通過設置數據庫的隔離級別,可以達到不同的隔離效果。
1.2.4 持久性(Durability):一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。
1.3 事務運行的三種模式
1.3.1 自動提交事務:默認事務管理模式。如果一個語句成功地完成,則提交該語句;如果遇到錯誤,則回滾該語句。
1.3.2 顯式事務:以BEGIN TRANSACTION顯式開始,以COMMIT或ROLLBACK顯式結束。
1.3.3 隱性事務:當連接以此模式進行操作時,sql將在提交或回滾當前事務后自動啟動新事務。無須描述事務的開始,只需提交或回滾每個事務。它生成連續的事務鏈。


2. 數據庫事務與事務日志
2.1 以mysql的innodb的事務為例,通過事務日志實現ACID特性。事務日志遵循WAL(Write-Ahead Logging 預寫日志方式)協議。
2.1.1 事務日志包括(參考:http://blog.sina.com.cn/s/blog_4e46604d0101gyzq.html)
重做日志redo:在Innodb存儲引擎中,事務日志是通過redo和innodb的存儲引擎日志緩沖(Innodb log buffer)來實現的,當開始一個事務的時候,會記錄該事務的lsn(log sequence number)號; 當事務執行時,會往InnoDB存儲引擎的日志的日志緩存里面插入事務日志;當事務提交時,必須將存儲引擎的日志緩沖寫入磁盤(通過innodb_flush_log_at_trx_commit來控制),也就是寫數據前,需要先寫日志。這種方式稱為“預寫日志方式”,innodb通過此方式來保證事務的完整性。也就意味着磁盤上存儲的數據頁和內存緩沖池上面的頁是不同步的,是先寫入redo log,然后寫入data file,因此是一種異步的方式。通過 show engine innodb status\G 來觀察之間的差距。記錄文件是ib_logfile0 ib_logfile1

回滾日志undo:用於事務的回滾,undo的記錄正好與redo的相反,insert變成delete,update變成相反的update,redo放在redo file里面。而undo放在一個內部的一個特殊segment上面,存儲與共享表空間內(ibdata1或者ibdata2中)。

 

Innodb_log_buffer_size 重做日志緩存大小

Innodb_log_file_size redo log文件大小  文件越大 數據恢復的時間越長
Innodb_log_file_group redo log文件數量 默認是2個 ib_logfile0 ib_logfile1
 
2.1.2 事務日志恢復事務:一般情況下,mysql在崩潰之后,重啟服務,innodb通過回滾日志undo將所有已完成並寫入磁盤的未完成事務進行rollback,然后redo中的事務全部重新執行一遍即可恢復數據,但是隨着redo的量增加,每次從redo的第一條開始恢復就會浪費長的時間,所以引入了checkpoint機制(如果在某個時間點,臟頁的數據被刷新到了磁盤,系統就把這個刷新的時間點記錄到redo log的結尾位置,在進行恢復數據的時候,checkpoint時間點之前的數據就不需要進行恢復了,可以縮短時間)
2.1.3 Dirty page:臟頁
一般業務運行過程中,當業務需要對某張的某行數據進行修改的時候,innodb會先將該數據從磁盤讀取到緩存中去,然后在緩存中對這條數據進行修改,這樣緩存中的數據就和磁盤的數據不一致了,這個時候緩存中的數據就稱為dirty page,只有當臟頁統一刷新到磁盤中才會是clean page

3. 數據庫事務是如何實現並發的





4. 數據庫事務隔離級別與鎖的關系

 

 

 

mysql innodb事務死鎖:

   事務A需要先查詢數據1,然后修改數據2;

   事務B需要先查詢數據2,然后修改數據1;

此時2個事務並發執行,由於mysql innodb的默認隔離級別是可重復讀,讀鎖、寫鎖只能在事務結束才會釋放。

事務A中需要等待事務B釋放數據2的共享鎖,才能執行對數據2添加排他鎖;事務B需要等待事務A釋放數據1的共享鎖,才能執行對數據1添加排他鎖。這樣會就出現事務死鎖

 

這種死鎖在oracle中就不會出現,因為oracle的默認隔離級別是讀已提交,共享鎖在執行完查詢之后就會釋放,不會導致排他鎖無法添加的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM