sybase 事务插入时不可查询_InnoDB事务与锁
事務(wù)
可以理解為數(shù)據(jù)庫(kù)執(zhí)行的一個(gè)最基礎(chǔ)的單位,其包含有限的操作命令(crud)。
事務(wù)的屬性(ACID):事務(wù)必須滿足四個(gè)屬性,原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)
原子性:要么執(zhí)行完全結(jié)束,要么全部不執(zhí)行。避免數(shù)據(jù)執(zhí)行不完全帶來(lái)的錯(cuò)誤數(shù)據(jù),所以事務(wù)必須具有原子性(commit、rollback)。即在事務(wù)A提交之前,如果發(fā)生錯(cuò)誤,則需要回退到事務(wù)執(zhí)行前的狀態(tài)。
一致性:指的是事務(wù)在執(zhí)行的前后,數(shù)據(jù)庫(kù)的數(shù)據(jù)一定會(huì)保持一致性的狀態(tài)??梢岳斫鉃橄到y(tǒng)從一種狀態(tài)轉(zhuǎn)變?yōu)榱硪环N狀態(tài)。事務(wù)A在提交之后,對(duì)系統(tǒng)的改變,事務(wù)B一定會(huì)感知到相同的變化。
隔離性:指的是事務(wù)之間的執(zhí)行相互獨(dú)立。在并發(fā)多個(gè)事務(wù)執(zhí)行的時(shí)候,每個(gè)事務(wù)內(nèi)部的操作不會(huì)影響到其他的事務(wù)。事務(wù)的執(zhí)行可以抽象為串行執(zhí)行(這里是修改上的串行)。針對(duì)不同情況,事務(wù)的隔離會(huì)有不同的隔離級(jí)別。
持久性:事務(wù)一旦提交成功就會(huì)被更新到到數(shù)據(jù)庫(kù),不會(huì)再被回退。
=================================================================
事務(wù)的隔離性級(jí)別:
針對(duì)并發(fā)執(zhí)行的事務(wù),會(huì)出現(xiàn)以下問(wèn)題:(臟讀、不可重復(fù)讀、幻讀)
1.臟讀:事務(wù)A讀取事務(wù)B更新的數(shù)據(jù),數(shù)據(jù)B進(jìn)行了回滾操作,那么A讀取到的數(shù)據(jù)是回滾前的數(shù)據(jù)是臟數(shù)據(jù)。
2.不可重復(fù)讀:在一次事務(wù)中,前后兩次查詢的數(shù)據(jù)不一致。主要是在事務(wù)未提交前,有其他的事務(wù)進(jìn)行了更新提交操作。
3.幻讀:事務(wù)A在對(duì)系統(tǒng)進(jìn)行更新以后,事務(wù)B對(duì)系統(tǒng)進(jìn)行了插入或者刪除操作,導(dǎo)致事務(wù)A發(fā)現(xiàn)仍有數(shù)據(jù)未更新,如同幻覺(jué)。
四種事務(wù)隔離級(jí)別:(處理并發(fā)問(wèn)題)
隔離級(jí)別 臟讀 不可重復(fù)讀 幻讀
讀未提交 是 是 是
讀已提交 否 是 是
可重復(fù)讀 否 否 是
可串行化 否 否 否
讀未提交(Read Uncommitted):在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。事務(wù)A可以讀取事務(wù)B未提交的數(shù)據(jù),如果事務(wù)B回滾,此時(shí)A讀取的數(shù)據(jù)即為臟數(shù)據(jù)。
讀已提交(Read Committed):事務(wù)A只能讀取事務(wù)B,或者其他事務(wù)已經(jīng)提交的數(shù)據(jù)。所以不會(huì)出現(xiàn)臟讀的數(shù)據(jù),但是會(huì)出現(xiàn)前后兩次不一致的不可重復(fù)讀,或者幻讀。
可重復(fù)讀 (Repeatable Read):這是MySQL的默認(rèn)事務(wù)隔離級(jí)別,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行。這是因?yàn)镸VCC機(jī)制,select讀取不會(huì)更改版本號(hào),是快照讀,而insert、update和delete會(huì)更新版本號(hào),是當(dāng)前讀(當(dāng)前版本)(注意,這里不會(huì)破壞數(shù)據(jù)的一致性)。無(wú)法解決幻讀的現(xiàn)象。
可串行化(Serializable):當(dāng)事務(wù)A開啟此隔離的級(jí)別時(shí)候,當(dāng)其他事務(wù)插入一條記錄報(bào)錯(cuò),表會(huì)被鎖了插入失敗,mysql中事務(wù)隔離級(jí)別為serializable時(shí)會(huì)鎖整個(gè)表,防止幻讀的出現(xiàn),但是完全的串行換操作會(huì)導(dǎo)致效率極低,一般不會(huì)使用此隔離級(jí)別。
=================================================================
設(shè)置全局事務(wù)隔離級(jí)別:
>SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; >SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; >SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ; >SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;設(shè)置當(dāng)前會(huì)話事務(wù)隔離級(jí)別:
>set session transaction isolation level READ UNCOMMITTED; >set session transaction isolation level READ COMMITTED; >set session transaction isolation level REPEATABLE READ; >set session transaction isolation level SERIALIZABLE;查詢事務(wù)隔離級(jí)別分析工具:
>show variables like '%iso%'; >select @@global.transaction_isolation;事務(wù)隔離級(jí)別加鎖分析
鎖的類型:
鎖模式
共享鎖(share(S) Lock):
SELECT ... LOCK IN SHARE MODE- 排他鎖(exclusive(X) Lock):
- 意向鎖(Intention Locks):表級(jí)別的鎖,自動(dòng)施加,自動(dòng)釋放。
鎖在細(xì)力度上又可以分為 表鎖和行鎖
共享鎖(share(S) Lock):共享鎖,顧名思義此對(duì)象鎖是可以共享的,即事務(wù)A對(duì)數(shù)據(jù)加上共享鎖以后,其它事務(wù)也可以加上共享鎖,但是不能加排它鎖。共享鎖只能讀,不能修改數(shù)據(jù)。(行鎖)。
排他鎖(exclusive(X) Lock):當(dāng)且只有一個(gè)事務(wù)可以對(duì)數(shù)據(jù)加鎖,而其他事務(wù)不能再加任何類型的鎖,排他鎖可以讀,也可以寫。(行鎖)。
意向鎖(Intention Locks):表級(jí)別的鎖,是在數(shù)據(jù)庫(kù)的某行加鎖(s或者x)的獲取時(shí)候,自動(dòng)加上意向鎖(IS或者IX),記錄有此類(s或者x)鎖。(表級(jí)別鎖不會(huì)和行級(jí)別鎖沖突)
為什么要使用意向鎖:當(dāng)事務(wù)要加入一個(gè)表級(jí)鎖的時(shí)候,我們需要遍歷每一行看一看是否有其他鎖防止沖突,如果數(shù)據(jù)量較大那么性能將會(huì)極低,所以加上意向鎖可以直接判斷是否有意向鎖即可。
獲得鎖
1.事務(wù)在獲得某個(gè)數(shù)據(jù)的S鎖,必須先獲得一個(gè)IS或者更強(qiáng)的鎖
2.事務(wù)在獲得某個(gè)數(shù)據(jù)的X鎖,必須先獲得表的IX鎖
加鎖
事務(wù)在加入表級(jí)鎖時(shí),先判斷是否有X、IX、S、IS鎖,有則失敗
X IX S IS
X Conflict Conflict Conflict Conflict
IX Conflict Compatible Conflict Compatible
S Conflict Conflict Compatible Compatible
IS Conflict Compatible Compatible Compatible
可以看出,共享鎖S是兼容S和IS的。IS與IX意向鎖是對(duì)表加鎖相互兼容的。
=================================================================
鎖的類型
記錄鎖(Record Locks):innoDB的行鎖是對(duì)索引的加鎖,innoDB是一個(gè)聚簇索引使用的是B+樹來(lái)進(jìn)行實(shí)現(xiàn)的,所以innoDB的鎖只有在使用索引的條件時(shí)候,才會(huì)加鎖,即便是不同行但是相同索引也會(huì)有沖突。當(dāng)不使用索引時(shí),則會(huì)使用表鎖。
間隙鎖(Gap Locks):對(duì)索引項(xiàng)之間的"間隙"加鎖,不包括索引項(xiàng)本身(左右開區(qū)間)。e.g. SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE; GAP鎖會(huì)阻止其他事務(wù)進(jìn)行的插入操作,不會(huì)阻止其他事務(wù)獲取相同間隙的gap鎖并且gap S-lock和gap X-lock不沖突。
Next-Key Locks : Next-Key 鎖 = 記錄鎖+間隙鎖。鎖定一個(gè)范圍并且鎖定記錄本身索引。InnoDB的默認(rèn)加鎖方式。
插入意向鎖(Insert Intention Locks):是間隙鎖的一種,在插入一條記錄之前,需要先拿到插入間隙的插入意向鎖。當(dāng)其他事務(wù)持有目標(biāo)間隙的Gap鎖時(shí)會(huì)阻塞。
=================================================================
MVCC(Multiversion Concurrency Control)多版本并發(fā)控制
作用:實(shí)現(xiàn)了讀不加鎖不會(huì)導(dǎo)致阻塞,寫加鎖,讀寫不沖突,在讀多寫少的場(chǎng)景下極大的提高了其效率,增加了其并發(fā)性。RC和RR級(jí)別使用。
實(shí)現(xiàn):在每一行記錄的后面增加兩個(gè)隱藏列,記錄創(chuàng)建版本號(hào)和刪除版本號(hào)。每個(gè)事務(wù)都有唯一的遞增版本號(hào),那么每一操作的創(chuàng)建版本號(hào)或者刪除版本號(hào)都會(huì)使用事務(wù)的版本號(hào)。
=================================================================
- INSERT:InnoDB為每個(gè)新增行記錄當(dāng)前事務(wù)編號(hào)作為創(chuàng)建ID
- UPDATE:記錄修改當(dāng)前行的值,寫事務(wù)編號(hào),回滾指針指向undo log中的修改前的行
- DELETE:將刪除位置為刪除
- SELECT:查詢出數(shù)據(jù)行的版本小于等于當(dāng)前事務(wù)的版本號(hào)的數(shù)據(jù),如刪除位為刪除則表示已刪除
1.創(chuàng)建一個(gè)name=sql的數(shù)據(jù),事務(wù)號(hào)為1
>insert into test (name) values(1);id name create version delete version
1 sql 1
2.接著更新 這個(gè)數(shù)據(jù),使得name=innodb,其事務(wù)版本號(hào)為2。
具體操作 先把以前這條數(shù)據(jù)刪除,在插入新的數(shù)據(jù),使用版本號(hào)來(lái)標(biāo)記
>update test set name= 'innodb' where id=1;id name create version delete version
1 sql 1 2 (代表 這條數(shù)據(jù)已經(jīng)被刪除)
1 innodb 2
3.刪除操作,事務(wù)版本號(hào)為3
>delete test where id = 1;id name create version delete version
1 sql 1 2 (代表 這條數(shù)據(jù)已經(jīng)被刪除)
1 innodb 2 3 (代表 這條數(shù)據(jù)已經(jīng)被刪除)
4.查詢條件: 創(chuàng)建版本號(hào) < 當(dāng)前版本號(hào) < 刪除版本號(hào)
RR:在RR的時(shí)候,讀的是當(dāng)前的快照表,讀取的是固定版本(第一次select的版本)的數(shù)據(jù),所以一個(gè)事務(wù)內(nèi)的讀是一致的。但是 insert update delete操作的是當(dāng)前讀,是最新版本的數(shù)據(jù)。(快照讀)
RC:讀事務(wù)每次都讀取最近的版本,因此兩次對(duì)同一字段的讀可能讀到不同的數(shù)據(jù)(幻讀),但能保證每次都讀到最新的數(shù)據(jù)。(當(dāng)前讀)
快照讀:讀到的數(shù)據(jù)可能是歷史版本數(shù)據(jù)。
當(dāng)前讀:讀到的數(shù)據(jù)是最近版本數(shù)據(jù),特殊的讀操作,插入/更新/刪除操作,屬于當(dāng)前讀需要加鎖。
=================================================================
針對(duì)隔離級(jí)別加鎖分析
RU: Select不加鎖,寫加X(jué)鎖
RC: Select快照讀不加鎖,寫加X(jué)鎖
RR: Select快照讀不加鎖,寫加X(jué) Next-key鎖
Serializable: Select加S Next-key鎖,寫加X(jué) Next-key鎖
=================================================================
RU與RC:區(qū)別在于快照讀與無(wú)快照讀
RC與RR:一致性讀肯定是讀取在某個(gè)時(shí)間點(diǎn)已經(jīng)提交了的數(shù)據(jù),RC的時(shí)間點(diǎn)為當(dāng)前時(shí)間點(diǎn),RR的時(shí)間點(diǎn)是第一次select的時(shí)間點(diǎn)
RR與Serializable:RR通過(guò)快照讀,讀取的都是過(guò)去某個(gè)時(shí)間點(diǎn)的快照,而Serializable級(jí)別下都是加了S鎖的讀,督導(dǎo)的都是當(dāng)前時(shí)間點(diǎn)的,這意味著在提交前,其他事務(wù)無(wú)法進(jìn)行提交。
=================================================================
死鎖
從圖中,可以看到一個(gè)Update操作的具體流程:當(dāng)Update SQL被發(fā)給MySQL后,MySQL Server會(huì)根據(jù)where條件,讀取第一條滿足條件的記錄,然后InnoDB引擎會(huì)將第一條記錄返回,并加鎖(current read).待MySQL Server收到這條加鎖的記錄之后,會(huì)再發(fā)起一個(gè)Update請(qǐng)求,更新這條記錄.一條記錄操作完成,再讀取下一條記錄,直至沒(méi)有滿足條件的記錄為止.因此,Update操作內(nèi)部,就包含了一個(gè)當(dāng)前讀.
注:根據(jù)上圖的交互,針對(duì)一條當(dāng)前讀的SQL語(yǔ)句,InnoDB與MySQL Server的交互,是一條一條進(jìn)行的,因此,加鎖也是一條一條進(jìn)行的.先對(duì)一條滿足條件的記錄加鎖,返回給MySQL Server,做一些DML操作;然后在讀取下一條加鎖,直至讀取完畢.
單個(gè)SQL組成的事務(wù),從宏觀上來(lái)看,鎖是在這個(gè)語(yǔ)句上一次獲得的,但從底層實(shí)現(xiàn)上來(lái)看,是逐個(gè)記錄行查詢,得到符合條件的記錄即對(duì)該行記錄的索引加鎖.,而加鎖的過(guò)程是邊查邊加、逐行獲得。
這個(gè)一個(gè)數(shù)據(jù)庫(kù)的設(shè)計(jì)原則,說(shuō)的是鎖操作分為兩個(gè)階段:加鎖階段與解鎖階段,并且保證加鎖階段與解鎖階段不相交。在一個(gè)事務(wù)中先加鎖執(zhí)行完操作,再統(tǒng)一在commit前釋放所有的鎖。
RC與RR的區(qū)別,RC級(jí)別下不會(huì)加GAP鎖,RR級(jí)別下會(huì)加GAP鎖
兩個(gè)表、兩行記錄,交叉獲得和申請(qǐng)互斥鎖,相同表記錄行鎖沖突:事務(wù)A按照一定順序加鎖,事務(wù)B按照相反的順序加鎖就會(huì)出現(xiàn)死鎖
如何避免死鎖
- 在程序中添加對(duì)死鎖的重試
- 完成相關(guān)變動(dòng)后盡早提交事務(wù)
- 修改多表或同表的多行數(shù)據(jù)時(shí),按照一定的順序
- 添加合適的索引
- 一切都沒(méi)用則可以使用表鎖
總結(jié)
以上是生活随笔為你收集整理的sybase 事务插入时不可查询_InnoDB事务与锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python类与继承person类_关于
- 下一篇: mysql 降序_MySQL 8 新特性