mysql事務詳細介紹
簡介
事務是由一組sql語句組成的邏輯處理單元
事務四個特性
原子性(Atomicity): 要么都成功要么都失敗 undo log實現(xiàn) 一致性(Consistent): 如轉賬前后兩個數(shù)額總合保持不變 隔離性(lsolation):數(shù)據庫提供一定的隔離機制,保證事務在不受外部并發(fā)操作影響的“獨立”環(huán)境下運行 鎖,mvcc多版本并發(fā)控制 持久性(Durable):事務提交持久化磁盤 redo log
事務隔離級別
數(shù)據庫的事務隔離級別有四種,分別是讀未提交,讀已提交,可重復讀,序列化,不同的隔離級別會產生臟讀,幻讀,不可重復讀等相關問題,因此,在選擇隔離級別的時候要根據應用場景來決定,使用不同的隔離級別
隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
事務隔離級別帶來的問題
臟讀(Dirty Reads一個事務訪問到了另外一個事務未提交的數(shù)據): 當一個事務正在訪問數(shù)據,并且對數(shù)據進行了修改,而這種修改還沒有提交到數(shù)據庫中,這時另一個事務也訪問這個數(shù)據,然后使用了這個數(shù)據。 不可重復度(Non-Repeatable Reads 一個事務兩次同樣的查詢,查詢到了不同的數(shù)據): 一個事務在讀取某些數(shù)據后的某個時間,再次讀取以前讀過的數(shù)據,發(fā)現(xiàn)和以前讀出的數(shù)據不一致 更新刪除 幻讀(Phantom Reads 一個事務兩次同樣的查詢,查詢到了不同的數(shù)據): 一個事務按照相同的查詢條件重新讀取以前查詢過的數(shù)據,卻發(fā)現(xiàn)其他事務插入了滿足其查詢條件的新數(shù)據 插入
驗證
查看事務的隔離級別show variables like ‘tx_isolation';
查看事務是否自動提交show variables like ‘autocommit';
關閉自動提交事務=0|OFF
set autocommit = 0;
臟讀:
設置事務隔離級別A、B set session transaction isolation level read uncommitted; sessionA 開啟事務 start transaction; 插入一條數(shù)據 INSERT INTO `db_test`.`t_user`(`id`, `name`) VALUES (5, 'DuQi'); sessionB 另一個連接進行查詢 select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ 此時連接B查詢到連接A未提交的事務的記錄id為5 到這里驗證了一個session讀取到了另一個事務未提交的數(shù)據
不可重復讀:
修改事務隔離級別 set session transaction isolation level read committed; A開啟事務 start transaction; 驗證更新 B執(zhí)行查詢語句 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ A執(zhí)行更新語句 update t_user set name = 'duqi' where id = 5; B執(zhí)行查詢語句 start transaction; MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ A提交事務 commit; B執(zhí)行查詢語句(同一個事務兩次查詢結果不一致) MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | duqi | +----+----------+ 繼續(xù)驗證刪除 A 開啟事務 B開啟事務 start transaction ; A刪除一條記錄 delete from t_user where id = 5; B事務查詢正常,查詢被刪除的記錄還在 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ A commit; B 繼續(xù)查詢 發(fā)現(xiàn)同一事物中多次查詢結果不一致 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | +----+----------+ 驗證插入 A、B 開啟事務 start transaction; A 插入記錄 INSERT INTO `db_test`.`t_user`(`id`, `name`) VALUES (5, 'DuQi'); B進行查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | +----+----------+ A提交事務 commit; B查詢 也是能查詢到A提交的事務 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+
幻讀:
修改事務隔離級別 set session transaction isolation level repeatable read; A、B開啟事務 start transaction; A插入一條數(shù)據 INSERT INTO `db_test`.`t_user`(`id`, `name`) VALUES (5, 'DuQi'); B查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | +----+----------+ A提交事務 commit; B事務查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ 可能發(fā)現(xiàn),不同事務之間,插入是可以查詢到的 咱們再繼續(xù)驗證更新和刪除 A、B開啟事務 A更新 update t_user set name = 'duqi' where id = 5; B查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ A提交事務commit B繼續(xù)查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | DuQi | +----+----------+ 咱們再繼續(xù)驗證刪除 A、B開啟事務 A事務執(zhí)行刪除操作 delete from t_user where id = 5; B事務執(zhí)行查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | duqi | +----+----------+ A提交事務,B繼續(xù)查詢 MySQL [db_test]> select * from t_user; +----+----------+ | id | name | +----+----------+ | 1 | ZhangSan | | 2 | LiSi | | 3 | WangWu | | 4 | LaoWang | | 5 | duqi | +----+----------+ 可能大家會發(fā)現(xiàn),REPEATABLE-READ 事務隔離級別解決了刪除和更新的問題,但是插入的問題一直存在。
MVCC
多版本并發(fā)控制。MVCC是一種并發(fā)控制的方法,一般在數(shù)據庫管理系統(tǒng)中,實現(xiàn)對數(shù)據庫的并發(fā)訪問,在編程語言中實現(xiàn)事務內存
mvcc在Mysql INNODB中的實現(xiàn)主要是為了提高數(shù)據庫并發(fā)性能,用更好的方式去處理讀寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞并發(fā)讀。
了解mvcc之前首先要了解兩個概念,什么是當前讀,什么是快照讀
當前讀
讀取最新版本的數(shù)據
像select lock in share mode(共享鎖),select for update;update、insert、delete(排他鎖)這些操作都是一種當前讀, 為什么叫當前讀? 就是它讀取的是記錄的最新版本,讀取時還要保證其他并發(fā)事務不能修改當前記錄,會對讀取的記錄進行加鎖
快照讀
讀取歷史版本的數(shù)據
像不加鎖的select操作就是快照讀,既不加鎖的非阻塞讀; 快照讀的前提是隔離級別不是串行級別,串行級別下的快照讀會退化成當前讀; 之所以出現(xiàn)快照讀的情況,是基于提高并發(fā)性能的考慮,快照讀的實現(xiàn)是基于多版本控制并發(fā)控制,既MVCC,可以認為mvcc是行鎖的一個變種,但它在很多情況下避免了加鎖操作,降低了開銷;
當前讀、快照讀、MVCC關系
MVCC多版本并發(fā)控制指的是維持一個數(shù)據的多個版本,使得讀寫操作沒有沖突,快照讀是mysql為實現(xiàn)mvcc的一個非阻塞讀功能。 mvcc模塊在Mysql中的具體實現(xiàn)是由三個隱式字段,undo日志,readview三個組件來實現(xiàn)的。
這里補充一點:三個隱式字段中其中有一個是列的唯一標志。有些同學設計表的時候一定要加主鍵(列依賴主鍵),即使它幾乎無用處也要加上。其實對于配置表,幾乎不進行增刪操作的表完全沒必要加主鍵,mysql在插入數(shù)據的時候會進行判斷表有無主鍵,如果有主鍵會使用主鍵作為唯一標示,如果沒有主鍵,會自動生成7byte大小的主鍵,所以表的合理性要根據不用使用場景進行設計。
mvcc 解決的問題
并發(fā)場景
1、讀讀:不存在任何問題,也不需要并發(fā)控制 2、讀寫:有線程安全問題,可能會造成事務隔離級別問題,可能遇到臟讀、不可重復讀、幻讀 3、寫寫:有線程安全問題,可能存在更新丟失問題
解決的問題
1、在并發(fā)讀寫數(shù)據庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數(shù)據庫并發(fā)讀寫的性能 2、解決臟讀、幻讀、不可重復讀等事務隔離問題,但是不能解決更新丟失問題
MVCC實現(xiàn)原理
mvcc的實現(xiàn)原理主要依賴于記錄中的三個隱藏字段、undolog,read view來實現(xiàn)的。
隱藏字段
行記錄除了我們自定義的字段外,還有數(shù)據庫隱式定義的DB_TRX_ID,BD_ROLL_PTR,DB_ROW_ID等字段
DB_TRX_ID 最近修改事務id: 6字節(jié),記錄創(chuàng)建這條記錄或者最后一次修改該記錄的事務id DB_ROLL_PTR 回滾指針: 7字節(jié),指向這條記錄的上一個版本,用于配合undolog,指向上一個舊版本 DB_ROW_ID 隱藏主鍵: 6字節(jié),如果數(shù)據庫表沒有主鍵,那么innodb會自動生成一個6字節(jié)的row_id
undo log
undo log被稱之為回滾日志,表示進行insert,delete,update操作的時候產生的方便回滾日志
當進行insert操作的時候,產生的undo log只在事務回滾的時候需要,并且在事務提交之后可以被立刻丟棄 當進行update和delete操作的時候,產生的undo log不僅僅在事務回滾的時候需要,在快照讀的時候也需要,所以不能隨便刪除,只有在快照讀或事務回滾不涉及該日志時,對應的日志才會被purge線程統(tǒng)一清除(當數(shù)據發(fā)生更新和刪除操作的時候都只是設置一下老記錄,如果某個記錄的deleted_id為true,并且DB_TRX_ID相對于purge線程的read view可見,那么這條記錄一定可以被清除的)
原理
當進行insert操作時,會生成對應delete語句 當進行delete操作時,會備份原數(shù)據的insert語句 當進行update時,會記錄原數(shù)據的update語句 這樣操作方便記錄回滾
read View
READ View是事務進行快照讀操作的時候產生的讀視圖,在該事務執(zhí)行快照的那一刻,會生成一個數(shù)據系統(tǒng)當前的快照,記錄并維護系統(tǒng)當前活躍事務的id,事務的id值是遞增的。
DB_ROW_ID | DB_TRX_ID | DB_ROLL_PTR | c_name | i_age | … |
---|---|---|---|---|---|
1 | 1 | zhangsan1 | 18 | … | |
2 | 2 | 1 | zhangsan2 | 19 | … |
READ VIEW的最大作用是用來做可見性判斷的,也就是說當某個事務在執(zhí)行快照讀的時候,對該記錄創(chuàng)建一個Read View的視圖,把它當作條件去判斷當前事務能夠看到哪個版本的數(shù)據,有可能讀取到的是最新的數(shù)據,也有可能讀取到的是最新的數(shù)據,也有可能讀取的是當前記錄的undolog中某個版本的數(shù)據 read view遵循的可見性算法主要是將要被修改的數(shù)據的最新記錄中的DB_TRX_ID取出來,與系統(tǒng)當前其他活躍事務的id去對比,如果DB_TRX_ID跟READ VIEW的屬性做了比較,不符合可見性,那么就通過DB_ROLL_PTR回滾指針去取出undolog中的DB_TRX_ID做比較,既遍歷鏈表中的DB_TRX_ID,直到找到滿足條件的DB_TRX_ID,這個DB_TRX_ID所在的舊記錄就是當前事務能看到的最新老版本數(shù)據
可見性規(guī)則
了解可見性規(guī)則之前首先要了解下Read View中的三個全局屬性
trx_list: 一直數(shù)值列表,用來維護Read View生成時刻系統(tǒng)正活躍的事務ID up_limit_id: 記錄trx_list列表中事務ID的最小ID low_limit_id: Read View生成時刻系統(tǒng)尚未分配下一個事務ID
比較規(guī)則
1、首先判斷DB_TRX_ID < up_limit_id,如果小于,則當前事務能看到DB_TRX_ID所在的記錄,如果大于等于進入下一個判斷 2、判斷DB_TRX_ID >= low_limit_id,如果大于等于則代表DB_TRX_ID所在的記錄在Read View生成后才出現(xiàn)的,那么對于當前事務肯定不可見,如果小于,進入下一步判斷 3、判斷DB_TRX_ID是否在活躍事務中,如果在,則代表在Read View生成時刻,這個事務還是活躍狀態(tài),還沒有commit,修改的數(shù)據,當前事務也是看不到,如果不在,則說明這個事務在Read View生成之前就已經開始commit,那么修改的結果是能夠看到的。
到此這篇關于mysql事務詳細介紹的文章就介紹到這了,更多相關mysql事務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mysql show processlist 顯示mysql查詢進程
processlist命令的輸出結果顯示了有哪些線程在運行,可以幫助識別出有問題的查詢語句,兩種方式使用這個命令2012-03-03Mysql在Windows系統(tǒng)快速安裝部署方法(綠色免安裝版)
這篇文章主要介紹了Mysql在Windows系統(tǒng)快速安裝部署方法(綠色免安裝版),需要的朋友可以參考下2017-06-06關于MySQL中datetime和timestamp的區(qū)別解析
在MySQL中一些日期字段的類型選擇為datetime和timestamp,那么對于這兩種類型不同的應用場景是什么呢,這篇文章主要介紹了關于MySQL中datetime和timestamp的區(qū)別解析,需要的朋友可以參考下2023-06-06解析如何使用Zend Framework 連接數(shù)據庫
本篇文章是對如何使用Zend Framework 連接數(shù)據庫的方法進行了詳細的分析介紹,需要的朋友參考下2013-06-06