事務介紹
首先,什么是事務?事務就是一段sql 語句的批處理,但是這個批處理是一個atom(原子),不可分割,要么都執行,要么回滾(rollback)都不執行。
MySQL 事務主要用於處理操作量大,復雜度高的數據。比如說,在人員管理系統中,你刪除一個人員,你即需要刪除人員的基本資料,也要刪除和該人員相關的信息,如信箱,文章等等,這樣,這些數據庫操作語句就構成一個事務!
- 在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。
- 事務處理可以用來維護數據庫的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行。
- 事務用來管理 insert,update,delete 語句
一般來說,事務是必須滿足4個條件(ACID): Atomicity(原子性)、Consistency(穩定性)、Isolation(隔離性)、Durability(可靠性)
- 1、事務的原子性:一組事務,要么成功;要么撤回。
- 2、穩定性 :有非法數據(外鍵約束之類),事務撤回。
- 3、隔離性:事務獨立運行。一個事務處理后的結果,影響了其他事務,那么其他事務會撤回。事務的100%隔離,需要犧牲速度。
- 4、可靠性:軟、硬件崩潰后,InnoDB數據表驅動會利用日志文件重構修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 選項 決定什么時候吧事務保存到日志里。
事務並發並不進行事務隔離造成的臟讀、幻讀、不可重復讀
- 臟讀:事務A讀到未提交事務B修改的數據,如果此時事務B中途執行失敗回滾,那么此時事務A讀取到的就是臟數據。比如事務A對money進行修改,此時事務B讀取到事務A的更新結果,但是如果后面事務A回滾,那么事務B讀取到的就是臟數據了。
- 不可重復讀:同一個事務中,對同一份數據讀取的結果不一致。事務A在事務B對數據更新前進行讀取,然后事務B更新提交,事務A再次讀取,這時候兩次讀取的數據不同。
- 幻讀:(同一個事務中,同一個查詢多次返回的結果不一樣。事務B查詢表的記錄數,然后事務A對表插入一條記錄,接着事務B再次查詢發現記錄數不同。注意這個解釋是不正確,網絡上有很多這樣的解釋,包括我認為比較權威的專家,但是經過實驗發現並不正確。所以這是需要注意的)。可以做這樣一個實驗,事務A查詢記錄數,事務B插入一條記錄(主鍵值為6),提交,然后事務A查詢記錄數,發現記錄數沒有改變,但是此時插入一條主鍵值為6的記錄發現沖突了,感覺像出現了幻覺。
區別
1、臟讀和不可重復讀:臟讀是事務讀取了還未提交事務的更新數據。不可重復讀是同一個事務中,幾次讀取的數據不同。
2、不可重復讀和幻讀的區別:都是在同一個事務中,前者是幾次讀取數據不同,后者是幾次讀取數據整體不同。
隔離級別
隔離級別 | 作用 |
---|---|
Serializable(串行化) | 避免臟讀、不可重復讀、幻讀 |
Repeatable(可重復讀) | 避免臟讀、不可重復讀 |
Read committed(讀已提交) | 避免臟讀 |
Read uncommitted(讀未提交) | none |
- 隔離級別改變影響鎖的周期
- mysql支持上面4種隔離級別,默認為可重復讀
鎖
MySQL有三種鎖的級別:頁級、表級、行級。
MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);
BDB存儲引擎采用的是頁面鎖(page-level locking),但也支持表級鎖;
InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是采用行級鎖。
MySQL這3種鎖的特性可大致歸納如下:
1、表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。
表級鎖讓多線程可以同時從數據表中讀取數據,但是如果另一個線程想要寫數據的話,就必須要先取得排他訪問(默認加排他表鎖);(共享讀鎖(Table Read Lock))
更新數據時,必須要等到更新完成了,其他線程才能訪問(讀)這個表。(獨占寫鎖(Table Write Lock))
2、行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。
3、頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。
原則上數據表有一個讀鎖時,其它進程無法對此表進行更新操作,但在一定條件下,MyISAM表也支持查詢和插入操作的並發進行。
一般MyISAM引擎的表也支持查詢和插入操作的並發進行(原則上數據表有一個讀鎖時,其它進程無法對此表進行更新操作)
MyISAM引擎有一個系統變量concurrent_insert,專門用以控制其並發插入的行為,其值分別可以為0、1或2:
a、concurrent_insert為0,不允許並發插入。
b、concurrent_insert為1,如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個進程讀表的同時,另一個進程從表尾插入記錄。這也是MySQL的默認設置。
c、concurrent_insert為2,無論MyISAM表中有沒有空洞,都允許在表尾並發插入記錄。
如果有讀寫請求同時進行的話,MYSQL將會優先執行寫操作。這樣MyISAM表在進行大量的更新操作時(特別是更新的字段中存在索引的情況下),會造成查詢操作很難獲得讀鎖,從而導致查詢阻塞。
我們還可以調整MyISAM讀寫的優先級別:
a、通過指定啟動參數low-priority-updates,使MyISAM引擎默認給予讀請求以優先的權利。
b、通過執行命令SET LOW_PRIORITY_UPDATES=1,使該連接發出的更新請求優先級降低。
c、通過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優先級。
MyISAM使用的是 flock 類的函數,直接就是對整個文件進行鎖定(叫做文件鎖定),MyISAM的數據表是按照單個文件存儲的,可以針對單個表文件進行鎖定;
InnoDB使用的是 fcntl 類的函數,可以對文件中局部數據進行鎖定(叫做行鎖定),InnoDB是一整個文件,把索引、數據、結構全部保存在 ibdata 文件里,所以必須用行鎖定。
事物控制語句:
BEGIN或START TRANSACTION;顯式地開啟一個事務;
COMMIT;也可以使用COMMIT WORK,不過二者是等價的。COMMIT會提交事務,並使已對數據庫進行的所有修改稱為永久性的;
ROLLBACK;有可以使用ROLLBACK WORK,不過二者是等價的。回滾會結束用戶的事務,並撤銷正在進行的所有未提交的修改;
SAVEPOINT identifier;SAVEPOINT允許在事務中創建一個保存點,一個事務中可以有多個SAVEPOINT;
RELEASE SAVEPOINT identifier;刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常;
ROLLBACK TO identifier;把事務回滾到標記點;
SET TRANSACTION;用來設置事務的隔離級別。InnoDB存儲引擎提供事務的隔離級別有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。
MYSQL 事務處理主要有兩種方法:
1、用 BEGIN, ROLLBACK, COMMIT來實現
BEGIN 開始一個事務
ROLLBACK 事務回滾
COMMIT 事務確認
2、直接用 SET 來改變 MySQL 的自動提交模式:
SET AUTOCOMMIT=0 禁止自動提交 SET AUTOCOMMIT=1 開啟自動提交
注意點
1、如果事務中sql正確運行,后面沒有commit,結果是不會更新到數據庫的,所以需要手動添加commit。
2、如果事務中部分sql語句出現錯誤,那么錯誤語句后面不會執行。而我們可能會認為正確操作會回滾撤銷,但是實際上並沒有撤銷正確的操作,此時如果再無錯情況下進行一次commit,之前的正確操作會生效,數據庫會進行更新。
參考鏈接:
https://www.cnblogs.com/leonardchen/p/7048187.html
https://www.cnblogs.com/metoy/p/5545580.html
http://blog.csdn.net/andyxm/article/details/44810313