Mysql-innoDB存储引擎(事务,锁,MVCC)
innoDB的特性:
從圖中由上至下紅色框中的信息是:基于主鍵的聚集索引 ,數(shù)據(jù)緩存,外鍵支持(邏輯上建立外鍵),行級(jí)別鎖,MVCC多版本控制,事務(wù)支持。這些也是InnoDB最重要的特性。
事務(wù):
數(shù)據(jù)庫(kù)操作的最小工作單元,是作為單個(gè)邏輯工作單元執(zhí)行的一系列操作;事務(wù)是一組不可再分割的操作集合(工作邏輯單元)。典型事務(wù)場(chǎng)景(轉(zhuǎn)賬):這是兩個(gè)事務(wù)
update user_account set balance = balance - 1000 where userID = 3;
update user_account set balance = balance +1000 where userID = 1;
mysql中如何開啟事務(wù):
通過(guò)navicat使用命令 showvariables like ‘a(chǎn)utocommit’; 查看自動(dòng)提交是否開啟。當(dāng)開啟后執(zhí)行update語(yǔ)句會(huì)自動(dòng)提交,當(dāng)自動(dòng)提交是關(guān)閉的,可以通過(guò)以下方式來(lái)創(chuàng)建事務(wù)提交:
BEGIN;-- 這兩個(gè)二選一開啟事務(wù) START TRANSACTION; -- 這是一個(gè)事務(wù) UPDATE ...... UPDATE ......COMMIT;-- 提交或者回滾 ROLLBACK;begin / start transaction -- 手工開啟事務(wù)。
commit / rollback -- 事務(wù)提交或回滾。
set session autocommit = on/off; -- 從Session的角度設(shè)定事務(wù)是否自動(dòng)開啟。
JDBC 編程:
connection.setAutoCommit(boolean);
Spring 事務(wù)AOP編程:
expression=execution(com.gpedu.dao.*.*(..))
事務(wù)ACID特性:
- 原子性(Atomicity):最小的工作單元,整個(gè)工作單元要么一起提交成功,要么全部失敗回滾
- 一致性(Consistency):事務(wù)中操作的數(shù)據(jù)及狀態(tài)改變是一致的,即寫入資料的結(jié)果必須完全符合預(yù)設(shè)的規(guī)則,不會(huì)因?yàn)槌霈F(xiàn)系統(tǒng)意外等原因?qū)е聽顟B(tài)的不一致
- 隔離性(Isolation):數(shù)據(jù)并發(fā)的時(shí)候,一個(gè)事務(wù)所操作的數(shù)據(jù)在提交之前,對(duì)其他事務(wù)的可見(jiàn)性設(shè)定(一般設(shè)定為不可見(jiàn))
- 持久性(Durability):事務(wù)所做的修改就會(huì)永久保存,不會(huì)因?yàn)橄到y(tǒng)意外導(dǎo)致數(shù)據(jù)的丟失
事務(wù)并發(fā)帶來(lái)什么問(wèn)題:
先來(lái)看第一張圖:在下圖中,一張表中記錄只有一條,事務(wù)B修改該條記錄的 age字段,而此刻 事務(wù)A來(lái)查詢了,獲得的age是18,接著事務(wù)B 回滾了,這樣子就出現(xiàn)了臟讀問(wèn)題。
再來(lái)看第二個(gè)圖:事務(wù)A先查詢了數(shù)據(jù)信息,此刻事務(wù)B進(jìn)行了修改并提交,然后事務(wù)A又去查詢了一遍,這個(gè)時(shí)候就會(huì)出現(xiàn)不可重復(fù)讀的問(wèn)題。
第三張圖:通過(guò)范圍查詢獲得一條數(shù)據(jù),此刻事務(wù)B 插入了一條數(shù)據(jù),事務(wù)A又去查詢獲得了兩條數(shù)據(jù),此刻就發(fā)生了幻讀。
綜上,事務(wù)并發(fā)給我們帶來(lái)了三個(gè)主要問(wèn)題:臟讀,不可重復(fù)讀,幻讀。
事務(wù)的隔離級(jí)別:
- Read Uncommitted(未提交讀) --未解決并發(fā)問(wèn)題,事務(wù)未提交對(duì)其他事務(wù)也是可見(jiàn)的,臟讀(dirty read)。
- Read Committed(提交讀) --解決臟讀問(wèn)題,一個(gè)事務(wù)開始之后,只能看到自己提交的事務(wù)所做的修改,不可重復(fù)讀(nonrepeatableread)。
- Repeatable Read (可重復(fù)讀) --解決不可重復(fù)讀問(wèn)題在同一個(gè)事務(wù)中多次讀取同樣的數(shù)據(jù)結(jié)果是一樣的,這種隔離級(jí)別未定義解決幻讀的問(wèn)題。
- Serializable(串行化) --解決所有問(wèn)題,最高的隔離級(jí)別,通過(guò)強(qiáng)制事務(wù)的串行執(zhí)行。
設(shè)置read uncommitted級(jí)別:set session transaction isolation level read uncommitted;
?
innoDB對(duì)隔離級(jí)別的支持程度:
在InnoDB中隔離級(jí)別到底如何實(shí)現(xiàn)的呢? --通過(guò)鎖、MVCC。
InnoDB中的鎖:
鎖是用于管理不同事務(wù)對(duì)共享資源的并發(fā)訪問(wèn),InnoDB存儲(chǔ)引擎支持行鎖和表鎖(另類的行鎖,通過(guò)行鎖鎖住所有的行)。官方文檔:https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html。表鎖與行鎖的區(qū)別:
- 鎖定粒度:表鎖 > 行鎖
- 加鎖效率:表鎖 > 行鎖
- 沖突概率:表鎖 > 行鎖
- 并發(fā)性能:表鎖 < 行鎖
MYSQL innoDB鎖類型:
- l 共享鎖(行鎖):Shared Locks
- l 排它鎖(行鎖):Exclusive Locks
- l 意向共享鎖(表鎖):Intention Shared Locks
- l 意向排它鎖(表鎖):Intention Exclusive Locks
- l 自增鎖:AUTO-INC Locks
行鎖的算法:
- l 記錄鎖 Record Locks
- l 間隙鎖 Gap Locks
- l 臨鍵鎖 Next-key Locks
?共享鎖:
又稱為讀鎖,簡(jiǎn)稱S鎖,顧名思義,共享鎖就是多個(gè)事務(wù)對(duì)于同一數(shù)據(jù)可以共享一把鎖,都能訪問(wèn)到數(shù)據(jù),但是只能讀不能修改,加鎖釋鎖方式:
-- 共享鎖加鎖 BEGIN select * from users WHERE id=1 LOCK IN SHARE MODE; rollback; commit; -- 在以上的SQL枷鎖后未執(zhí)行提交或者回滾執(zhí)行其他事務(wù)執(zhí)行 select * from users where id =1; -- 可以執(zhí)行,共享鎖特性 update users set age=19 where id =1;--會(huì)阻塞排他鎖:
又稱為寫鎖,簡(jiǎn)稱X鎖,排他鎖不能與其他鎖并存,如一個(gè)事務(wù)獲取了一個(gè)數(shù)據(jù)行的排他鎖,其他事務(wù)就不能再獲取該行的鎖(共享鎖、排他鎖),只有該獲取了排他鎖的事務(wù)是可以對(duì)數(shù)據(jù)行進(jìn)行讀取和修改,(其他事務(wù)要讀取數(shù)據(jù)可來(lái)自于快照),加鎖釋鎖方式:delete / update / insert 默認(rèn)加上X鎖。
-- 自動(dòng)獲取排它鎖 set session autocommit = OFF; -- 設(shè)置手動(dòng)提交事務(wù) update users set age = 23 where id =1; --執(zhí)行該語(yǔ)句后未提交,在其他線程上,執(zhí)行下列其他事務(wù)執(zhí)行語(yǔ)句會(huì)處于阻塞commit; ROLLBACK;-- 手動(dòng)獲取排它鎖 set session autocommit = ON; begin select * from users where id =1 for update; commit;-- 其他事務(wù)執(zhí)行 select * from users where id =1 lock in share mode; select * from users where id =1 for update; select * from users where id =1;innoDB--行鎖到底鎖了什么?
首先先來(lái)看一下測(cè)試表的結(jié)構(gòu),其中用的是InnoDB引擎,有一個(gè)name的唯一索引,主鍵自增,有3條數(shù)據(jù)
DROP TABLE IF EXISTS `users`; CREATE TABLE `users` (`id` int(11) NOT NULL AUTO_INCREMENT,`uname` varchar(32) NOT NULL,`userLevel` int(11) NOT NULL,`age` int(11) NOT NULL,`phoneNum` char(11) NOT NULL,`createTime` datetime NOT NULL,`lastUpdate` datetime NOT NULL,PRIMARY KEY (`id`),KEY `idx_name` (`uname`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=100006 DEFAULT CHARSET=utf8mb4;-- ---------------------------- -- Records of users -- ---------------------------- INSERT INTO `users` VALUES ('1', '李二狗', '2', '18', '13666666666', '2018-12-01 15:39:46', '2018-12-01 15:39:50'); INSERT INTO `users` VALUES ('2', '張三豐', '1', '29', '13777777777', '2018-12-01 16:35:41', '2018-12-01 16:35:44'); INSERT INTO `users` VALUES ('3', '武大郎', '2', '44', '13888888888', '2018-12-01 16:36:01', '2018-12-01 16:36:03');案例1:緊接著在一個(gè)事務(wù)中執(zhí)行以下語(yǔ)句:可以發(fā)現(xiàn)我們把事務(wù)設(shè)置成手動(dòng)提交,但是我并未提交或者回滾:
set session autocommit = OFF; update users set lastUpdate=NOW() where phoneNum = '13666666666';然后在其他事務(wù)中執(zhí)行如下語(yǔ)句:會(huì)發(fā)現(xiàn),上述SQL執(zhí)行修改會(huì)獲得默認(rèn)的排它鎖,而此刻并未釋放,鎖的列是ID為1,然后我們下列要修改ID為2的數(shù)據(jù)也是出于阻塞,這是為什么呢?
update users set lastUpdate=NOW() where id =2; update users set lastUpdate=NOW() where id =1;案例2,執(zhí)行以下語(yǔ)句,可以發(fā)現(xiàn)我們把事務(wù)設(shè)置成手動(dòng)提交,但是我并未提交或者回滾:
set session autocommit = OFF; update users set lastUpdate=NOW() where id = 1;然后在其他事務(wù)上執(zhí)行:會(huì)發(fā)現(xiàn)下面2條SQL執(zhí)行后 第一條會(huì)順利執(zhí)行,而第二條會(huì)被阻塞。
update users set lastUpdate=NOW() where id =2; update users set lastUpdate=NOW() where id =1;案例三:執(zhí)行一下語(yǔ)句:
set session autocommit = OFF; update users set lastUpdate=NOW() where `name` = '李二狗';然后在其他事務(wù)上執(zhí)行:會(huì)發(fā)現(xiàn)前面兩條會(huì)執(zhí)行失敗,而后面兩條執(zhí)行成功
-- 其他查詢執(zhí)行 update users set lastUpdate=NOW() where `name` = '李二狗'; update users set lastUpdate=NOW() where id =1; update users set lastUpdate=NOW() where `name` = '張三豐'; update users set lastUpdate=NOW() where id =2;InnoDB的行鎖是通過(guò)給索引上的索引項(xiàng)加鎖來(lái)實(shí)現(xiàn)的。對(duì)于二級(jí)索引,會(huì)對(duì)一級(jí)索引也加鎖。只有通過(guò)索引條件進(jìn)行數(shù)據(jù)檢索,InnoDB才使用行級(jí)鎖,否則,InnoDB將使用表鎖(鎖住索引的所有記錄)表鎖:lock tables xx read/write;
意向共享鎖(IS):表示事務(wù)準(zhǔn)備給數(shù)據(jù)行加入共享鎖,即一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖,意向共享鎖之間是可以相互兼容的。
意向排它鎖(IX):表示事務(wù)準(zhǔn)備給數(shù)據(jù)行加入排他鎖,即一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖,意向排它鎖之間是可以相互兼容的。
意向鎖(IS、IX)是InnoDB數(shù)據(jù)操作之前自動(dòng)加的,不需要用戶干預(yù)。
意義:相當(dāng)于一個(gè)標(biāo)記flgs,當(dāng)事務(wù)想去進(jìn)行鎖表時(shí),可以先判斷意向鎖是否存在,存在時(shí)則可快速返回該表不能啟用表鎖。
自增鎖 AUTO-INC Locks:
針對(duì)自增列自增長(zhǎng)的一個(gè)特殊的表級(jí)別鎖,查看自增鎖默認(rèn)值:show variables like 'innodb_autoinc_lock_mode';默認(rèn)取值1,代表連續(xù),事務(wù)未提交ID永久丟失。當(dāng)級(jí)別為1,執(zhí)行一下SQL:在插入數(shù)據(jù)的時(shí)候,這個(gè)表的ID為自增,連續(xù)回滾3次,這3次的ID會(huì)永久消失,在下次執(zhí)行commit的時(shí)候ID會(huì)在原來(lái)的數(shù)值上加3.
begin; insert into users(name , age ,phoneNum ,lastUpdate ) values ('tom2',30,'1344444444',now()); ROLLBACK;針對(duì)行鎖的算法:
臨鍵鎖 Next-key Locks:
Next-key locks:InnoDB行鎖的默認(rèn)算法。鎖住記錄+區(qū)間(左開右閉),當(dāng)sql執(zhí)行按照索引進(jìn)行數(shù)據(jù)的檢索時(shí),查詢條件為范圍查找(between and、<、>等)并有數(shù)據(jù)命中則此時(shí)SQL語(yǔ)句加上的鎖為Next-key locks,鎖住索引的記錄+區(qū)間(左開右閉)。先來(lái)搞一張表:
DROP TABLE IF EXISTS `test`; CREATE TABLE `test` (`id` int(11) NOT NULL ,`name` varchar(32) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- ---------------------------- -- Records of users -- ---------------------------- INSERT INTO `test` VALUES ('1', '1'); INSERT INTO `test` VALUES ('4', '4'); INSERT INTO `test` VALUES ('7', '7'); INSERT INTO `test` VALUES ('10', '10');在InnoDB的默認(rèn)行級(jí)算法中會(huì)對(duì)數(shù)據(jù)行進(jìn)劃分:可以看到是一個(gè)左開右閉的這個(gè)一個(gè)展現(xiàn)。
執(zhí)行以下sql不提交:由于有數(shù)據(jù)命中則會(huì)鎖住(4,7](7,10] 兩個(gè)區(qū)間。未提交的情況下執(zhí)行下列其他事務(wù)中前四條全部阻塞而最后一條會(huì)成功執(zhí)行。
begin; select * from test where id>5 and id<9 for update; -- 其他事務(wù) select * from test where id=4 for update; -- 阻塞 select * from test where id=7 for update; -- 阻塞 select * from test where id=10 for update; -- 阻塞 INSERT INTO `test` (`id`, `name`) VALUES (9, '9'); -- 阻塞 INSERT INTO `test` (`id`, `name`) VALUES (11, '11');-- 成功為什么InnoDB要選擇(臨鍵鎖)Next-key locks作為InnoDB行鎖的默認(rèn)算法?解決幻讀,因?yàn)锽+Tree是有順序的,從左往右順序遞增,把臨鍵區(qū)間也鎖住,其他事務(wù)要往里插入數(shù)據(jù)是插不進(jìn)去的。
間隙鎖 Gap Locks:繼臨鍵鎖要是沒(méi)有命中數(shù)據(jù)的情況下:
Gap鎖只在?Repeatable Read (可重復(fù)讀)? 的隔離級(jí)別的情況下才存在。
記錄鎖 Record Locks:繼臨鍵鎖之后,在條件為精準(zhǔn)匹配的時(shí)候。
?
那么鎖是怎么解決上述產(chǎn)生 臟讀,不可重復(fù)讀,以及幻讀的情況呢?
解決臟讀:
解決不可重復(fù)讀:
解決幻讀:
死鎖:
- 多個(gè)并發(fā)事務(wù)(2個(gè)或者以上);
- 每個(gè)事務(wù)都持有鎖(或者是已經(jīng)在等待鎖);
- 每個(gè)事務(wù)都需要再繼續(xù)持有鎖;
- 事務(wù)之間產(chǎn)生加鎖的循環(huán)等待,形成死鎖
避免死鎖:
- 類似的業(yè)務(wù)邏輯以固定的順序訪問(wèn)表和行。
- 大事務(wù)拆小。大事務(wù)更傾向于死鎖,如果業(yè)務(wù)允許,將大事務(wù)拆小。
- 在同一個(gè)事務(wù)中,盡可能做到一次鎖定所需要的所有資源,減少死鎖概率。
- 降低隔離級(jí)別,如果業(yè)務(wù)允許,將隔離級(jí)別調(diào)低也是較好的選擇
- 為表添加合理的索引??梢钥吹饺绻蛔咚饕龑?huì)為表的每一行記錄添加上鎖(或者說(shuō)是表鎖)
Mysql 中MVCC版本控制:
MVCC是multiversion concurrency control的縮寫,并發(fā)訪問(wèn)(讀或?qū)?數(shù)據(jù)庫(kù)時(shí),對(duì)正在事務(wù)內(nèi)處理的數(shù)據(jù)做多版本的管理。以達(dá)到用來(lái)避免寫操作的堵塞,從而引發(fā)讀操作的并發(fā)問(wèn)題 。提供MySQL事物隔離級(jí)別下無(wú)鎖讀,例如一個(gè)事物在執(zhí)行update等修改數(shù)據(jù)的sql,并未提交時(shí)其他事物進(jìn)行數(shù)據(jù)讀取是不影響的,而且讀取內(nèi)容為數(shù)據(jù)變更之前的數(shù)據(jù)。
? MVCC多本版快照由innodb的rollback segment構(gòu)照的,一個(gè)sql進(jìn)行查找數(shù)據(jù)當(dāng)查找到某一個(gè)數(shù)據(jù)需要到回滾段中查找數(shù)據(jù)時(shí),就會(huì)根據(jù)當(dāng)前頁(yè)上行數(shù)據(jù)的一個(gè)指針到回滾段中查找對(duì)應(yīng)數(shù)據(jù),在innodb的表主鍵中都會(huì)存在三個(gè)隱藏的字段:
- ????DB_TRX_ID:該字段存儲(chǔ)最后一個(gè)修改該行數(shù)據(jù)的事務(wù)ID,占用6byte的空間,MySQL的delete操作是標(biāo)記刪除,所以對(duì)應(yīng)行數(shù)據(jù)的該字段就為一個(gè)刪除標(biāo)記。
- ????DB_ROLL_PTR:該字段就記錄執(zhí)行roll segment的指針信息,當(dāng)事務(wù)需要rollback時(shí)就通過(guò)該字段尋找記錄重新構(gòu)照行數(shù)據(jù),該字段占用7byte空間。
- ????DB_ROW_ID:記錄每個(gè)行ID,該ID值為單調(diào)遞增型整數(shù),在innodb表指定了主鍵之后DB_ROW_ID存在于主鍵索引上,如果無(wú)主鍵該值就不會(huì)存在,占用6byte空間。
? 在一個(gè)sql進(jìn)行查詢時(shí),讀取到一行數(shù)據(jù)的DB_TRX_ID值和自己事物ID的對(duì)比,假如隔離級(jí)別為MySQL的默認(rèn)級(jí)別,就只讀取該ID值小于本身事物ID的數(shù)據(jù),其余數(shù)據(jù)就需要通過(guò)DB_ROLL_PTR的信息到回滾段中讀取。MVCC是否起到相應(yīng)的作用需取決于數(shù)據(jù)庫(kù)隔離級(jí)別的配置。
? 在insert和update、delete的操作是有區(qū)別的,一個(gè)insert語(yǔ)句插入數(shù)據(jù)再rollback就是直接對(duì)undo log的刪除,他并不會(huì)影響其他事物的讀取操作,而update、delete操作是在原有數(shù)據(jù)做更改,可能有其他事物在對(duì)該行數(shù)據(jù)做讀取操作,所以u(píng)pdate、delete產(chǎn)生的undo log數(shù)據(jù)是由內(nèi)部線程自動(dòng)清理,在該數(shù)據(jù)無(wú)任何事務(wù)在使用時(shí)清理掉,所以在undo log中insert和update、delete產(chǎn)生的數(shù)據(jù)存于不同位置。
下面通過(guò)一個(gè)案例來(lái)熟悉一下MVCC的效果:
-- 數(shù)據(jù)準(zhǔn)備 insert into teacher(name,age) value ('seven',18) ;--假設(shè)事務(wù)版本為1 insert into teacher(name,age) value ('qing',20) ;--假設(shè)事務(wù)版本為1 begin; ----------1 select * from users ; ----------2begin; ----------3 update teacher set age =28 where id =1;----------4在每一行數(shù)據(jù) 插入數(shù)據(jù)表的時(shí)候,都會(huì)開啟一個(gè)事務(wù),每一行數(shù)據(jù)都會(huì)保存執(zhí)行的時(shí)候所獲取的事務(wù)版本號(hào),當(dāng)進(jìn)行修改的時(shí)候會(huì)先copy一份待修改的數(shù)據(jù)到 Undo 緩沖區(qū),在提交后然寫入磁盤,在此過(guò)程中會(huì)將原先的數(shù)據(jù)行的刪除版本號(hào)置為當(dāng)前事務(wù)ID,然后再在新的數(shù)據(jù)行把數(shù)據(jù)行版本號(hào)置為當(dāng)前事務(wù)ID。
當(dāng)我們按照 1,2,3,4,2 的順序去執(zhí)行的時(shí)候,首先執(zhí)行 1 拿到的事務(wù)ID 是2,那么執(zhí)行2查詢出來(lái)就是原始數(shù)據(jù),這個(gè)時(shí)候事務(wù)并沒(méi)有提交或者回滾,然后執(zhí)行3開啟一個(gè)事務(wù)拿到的事務(wù)ID 為3 ,此刻執(zhí)行4(在更新操作的時(shí)候,采用的是先標(biāo)記舊的那行記錄為已刪除,并且刪除版本號(hào)是事務(wù)版本號(hào),然后插入一行新的記錄的方式。)進(jìn)行 update 操作的時(shí)候會(huì) copy 數(shù)據(jù)到Undo 緩沖區(qū),然后將Undo.log的原始數(shù)據(jù)的刪除版本號(hào)置為3,把新數(shù)據(jù)的事務(wù)版本號(hào)置為3,再執(zhí)行2的時(shí)候由于此刻事務(wù)ID 還是為2,所以根據(jù)查詢規(guī)則查找數(shù)據(jù)行版本號(hào)小于當(dāng)前事務(wù)版本的數(shù)據(jù)行,查找刪除版本號(hào)大于當(dāng)前事務(wù)版本的或者刪除版本為nul的數(shù)據(jù)行,由于修改操作未提交,所以最終得到的結(jié)果數(shù)據(jù)還是原始數(shù)據(jù)的值,并不會(huì)把修改的數(shù)據(jù)加載回來(lái),解決了不可重復(fù)讀的問(wèn)題。
如果按照這樣的邏輯通過(guò) 3,4,1,2的順序去執(zhí)行,那么首先修改的操作會(huì)拿到事務(wù)ID為2,將原來(lái)的數(shù)據(jù)行copy出來(lái),將原來(lái)的刪除版本號(hào)置為當(dāng)前事務(wù)ID,接著將備份數(shù)據(jù)的版本號(hào)置為當(dāng)前版本號(hào),然后執(zhí)行查詢操作再開啟一個(gè)新事務(wù),拿到的事務(wù)ID為3,根據(jù)查詢規(guī)則,拿到的是進(jìn)行了update 操作但并未提交的新數(shù)據(jù),造成了臟讀,這是為什么呢?那么是由誰(shuí)去解決這個(gè)問(wèn)題的呢?其實(shí)這里面涉及到了 Undo.log的機(jī)制以及當(dāng)前讀,快照讀的問(wèn)題,那么接下來(lái)看看他們是怎么處理這個(gè)問(wèn)題的 。
Undo Log:
Undo Log 是什么:undo意為取消,以撤銷操作為目的,返回指定某個(gè)狀態(tài)的操作,undo log指事務(wù)開始之前,在操作任何數(shù)據(jù)之前,首先將需操作的數(shù)據(jù)備份到一個(gè)地方 (Undo Log),UndoLog是為了實(shí)現(xiàn)事務(wù)的原子性而出現(xiàn)的產(chǎn)物。
Undo Log實(shí)現(xiàn)事務(wù)原子性:事務(wù)處理過(guò)程中如果出現(xiàn)了錯(cuò)誤或者用戶執(zhí)行了 ROLLBACK語(yǔ)句,Mysql可以利用Undo Log中的備份將數(shù)據(jù)恢復(fù)到事務(wù)開始之前的狀態(tài)。
UndoLog在Mysql innodb存儲(chǔ)引擎中用來(lái)實(shí)現(xiàn)多版本并發(fā)控制。
Undo log實(shí)現(xiàn)多版本并發(fā)控制:事務(wù)未提交之前,Undo保存了未提交之前的版本數(shù)據(jù),Undo 中的數(shù)據(jù)可作為數(shù)據(jù)舊版本快照供其他并發(fā)事務(wù)進(jìn)行快照讀。
如下圖這樣的處理就避免了臟讀的問(wèn)題。
當(dāng)前讀,快照讀:
快照讀:SQL讀取的數(shù)據(jù)是快照版本,也就是歷史版本,普通的SELECT就是快照讀innodb快照讀,數(shù)據(jù)的讀取將由 cache(原本數(shù)據(jù)) + undo(事務(wù)修改過(guò)的數(shù)據(jù)) 兩部分組成
當(dāng)前讀:SQL讀取的數(shù)據(jù)是最新版本。通過(guò)鎖機(jī)制來(lái)保證讀取的數(shù)據(jù)無(wú)法通過(guò)其他事務(wù)進(jìn)行修改UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是當(dāng)前讀。
Redo Log:
Redo Log 是什么:Redo,顧名思義就是重做。以恢復(fù)操作為目的,重現(xiàn)操作;Redo log指事務(wù)中操作的任何數(shù)據(jù),將最新的數(shù)據(jù)備份到一個(gè)地方 (Redo Log)。
Redo log的持久:不是隨著事務(wù)的提交才寫入的,而是在事務(wù)的執(zhí)行過(guò)程中,便開始寫入redo 中。具體的落盤策略可以進(jìn)行配置.RedoLog是為了實(shí)現(xiàn)事務(wù)的持久性而出現(xiàn)的產(chǎn)物。
Redo Log實(shí)現(xiàn)事務(wù)持久性:防止在發(fā)生故障的時(shí)間點(diǎn),尚有臟頁(yè)未寫入磁盤,在重啟mysql服務(wù)的時(shí)候,根據(jù)redolog進(jìn)行重做,從而達(dá)到事務(wù)的未入磁盤數(shù)據(jù)進(jìn)行持久化這一特性。
? 流程圖如下:
指定Redo log 記錄在{datadir}/ib_logfile1&ib_logfile2 可通過(guò)innodb_log_group_home_dir 配置指定目錄存儲(chǔ)。一旦事務(wù)成功提交且數(shù)據(jù)持久化落盤之后,此時(shí)Redo log中的對(duì)應(yīng)事務(wù)數(shù)據(jù)記錄就失去了意義,所以Redo log的寫入是日志文件循環(huán)寫入的。
- 指定Redo log日志文件組中的數(shù)量 innodb_log_files_in_group 默認(rèn)為2
- 指定Redo log每一個(gè)日志文件最大存儲(chǔ)量innodb_log_file_size 默認(rèn)48M
- 指定Redo log在cache/buffer中的buffer池大小innodb_log_buffer_size 默認(rèn)16M
Redo buffer 持久化Redo log的策略, Innodb_flush_log_at_trx_commit:
- 取值 0 每秒提交 Redo buffer --> Redo log OS cache -->flush cache to disk[可能丟失一秒內(nèi)的事務(wù)數(shù)據(jù)]。
- 取值 1 默認(rèn)值,每次事務(wù)提交執(zhí)行Redo buffer --> Redo log OS cache -->flush cache to disk[最安全,性能最差的方式]。
- 取值 2 每次事務(wù)提交執(zhí)行Redo buffer --> Redo log OS cache 再每一秒執(zhí)行 ->flush cache todisk操作。
來(lái)源:https://www.cnblogs.com/wuzhenzhao/p/10348566.html
總結(jié)
以上是生活随笔為你收集整理的Mysql-innoDB存储引擎(事务,锁,MVCC)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一枝梅(说一说一枝梅的简介)
- 下一篇: 平滑重启更新(GR机制)