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