事務---學習筆記(2)
官方解釋
Transaction isolation is one of the foundations of database processing. Isolation is the I in the acronym ACID; the isolation level is the setting that fine-tunes the balance between performance and reliability, consistency, and reproducibility of results when multiple transactions are making changes and performing queries at the same time.
事務隔離是資料庫處理的基礎之一。隔離(Isolation )是縮寫詞ACID中的I;隔離級別是在多個事務同時進行更改或執行查詢時,對執行結果的效能與可靠性,一致性和可重現性之間的平衡進行微調的設定。
谷歌翻譯讀著有點拗口,理解下來大概就是隔離級別的設定是為了平衡資料庫效能和ACID特性,在這兩者間獲得一個最佳設定。
InnoDB offers all four transaction isolation levels described by the SQL:1992 standard: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABLE. The default isolation level for InnoDB is REPEATABLE READ.
InnoDB提供了SQL:1992標準描述的所有四個事務隔離級別:READ UNCOMMITTED,READ COMMITTED,REPEATABLE READ和SERIALIZABLE。 InnoDB的預設隔離級別是REPEATABLE READ。
四種隔離級別:讀未提交、讀已提交、可重複讀、序列化
A user can change the isolation level for a single session or for all subsequent connections with the SET TRANSACTION
statement. To set the server's default isolation level for all connections, use the --transaction-isolation
option on the command line or in an option file. For detailed information about isolation levels and level-setting syntax, see Section 13.3.7, “SET TRANSACTION Syntax”.
使用者可以使用SET TRANSACTION語句更改單個會話或所有後續連線的隔離級別。 要為所有連線設定伺服器的預設隔離級別,請在命令列或選項檔案中使用--transaction-isolation選項。 有關隔離級別和級別設定語法的詳細資訊,請參見第13.3.7節“SET TRANSACTION語法”。
InnoDB supports each of the transaction isolation levels described here using different locking strategies. You can enforce a high degree of consistency with the default REPEATABLE READ level, for operations on crucial data where ACID compliance is important. Or you can relax the consistency rules with READ COMMITTED or even READ UNCOMMITTED, in situations such as bulk reporting where precise consistency and repeatable results are less important than minimizing the amount of overhead for locking. SERIALIZABLE enforces even stricter rules than REPEATABLE READ, and is used mainly in specialized situations, such as with XA transactions and for troubleshooting issues with concurrency and deadlocks.
InnoDB使用不同的鎖定策略支援此處描述的每個事務隔離級別。 您可以使用預設的REPEATABLE READ級別強制執行高度一致性,以便對ACID合規性很重要的關鍵資料進行操作。 或者您可以放鬆使用READ COMMITTED甚至READ UNCOMMITTED的一致性規則,例如批量報告,其中精確一致性和可重複結果不如最小化鎖定開銷量重要。 SERIALIZABLE強制執行甚至比REPEATABLE READ更嚴格的規則,主要用於特殊情況,例如XA事務以及併發和死鎖的故障排除問題。
根據不同的業務需求選擇不同的事務隔離級別。批量報告對精確事務一致性要求沒有最小化鎖定開銷重要,所以可以適當降低事務隔離級別。
The following list describes how MySQL supports the different transaction levels. The list goes from the most commonly used level to the least used.
以下列表描述了MySQL如何支援不同的事務級別。 該列表從最常用的級別變為最少使用的級別。
下面的順序是 REPEATABLE READ、READ COMMITTED、READ UNCOMMITTED、SERIALIZABLE;可重複讀、讀已提交、讀未提交、序列化;可見序列化雖然能保證資料一致性,但是使用並非最常見的,要綜合考慮業務和系統性能。
REPEATABLE READ
This is the default isolation level for InnoDB. Consistent reads within the same transaction read the snapshot established by the first read. This means that if you issue several plain (nonlocking) SELECT statements within the same transaction, these SELECT statements are consistent also with respect to each other. See Section 15.5.2.3, “Consistent Nonlocking Reads”.
For locking reads (SELECT with FOR UPDATE or FOR SHARE), UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition.
For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it.
For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range. For information about gap locks and next-key locks, see Section 15.5.1, “InnoDB Locking”.
這是InnoDB的預設隔離級別。 同一事務中的一致讀取讀取第一次讀取建立的快照。 這意味著如果在同一事務中發出幾個普通(非鎖定)SELECT語句,這些SELECT語句也相互一致。 請參見第15.5.2.3節“一致的非鎖定讀取”。
對於鎖定讀取(使用FOR UPDATE或FOR SHARE的SELECT),UPDATE和DELETE語句,鎖定取決於語句是使用具有唯一搜索條件的唯一索引還是範圍型別搜尋條件。
對於具有唯一搜索條件的唯一索引,InnoDB僅鎖定找到的索引記錄,而不是之前的間隙。
對於其他搜尋條件,InnoDB鎖定掃描的索引範圍,使用間隙鎖或下一鍵鎖來阻止其他會話插入範圍所覆蓋的間隙。 有關間隙鎖和下一鍵鎖的資訊,請參見第15.5.1節“InnoDB鎖定”。
READ COMMITTED
Each consistent read, even within the same transaction, sets and reads its own fresh snapshot. For information about consistent reads, see Section 15.5.2.3, “Consistent Nonlocking Reads”.
For locking reads (SELECT
with FOR UPDATE
or FOR SHARE
), UPDATE
statements, and DELETE
statements, InnoDB
locks only index records, not the gaps before them, and thus permits the free insertion of new records next to locked records. Gap locking is only used for foreign-key constraint checking and duplicate-key checking.
Because gap locking is disabled, phantom problems may occur, as other sessions can insert new rows into the gaps. For information about phantoms, see Section 15.5.4, “Phantom Rows”.
Only row-based binary logging is supported with the READ COMMITTED
isolation level. If you use READ COMMITTED
with binlog_format=MIXED
, the server automatically uses row-based logging.
Using READ COMMITTED
has additional effects:
-
For
UPDATE
orDELETE
statements,InnoDB
holds locks only for rows that it updates or deletes. Record locks for nonmatching rows are released after MySQL has evaluated theWHERE
condition. This greatly reduces the probability of deadlocks, but they can still happen. -
For
UPDATE
statements, if a row is already locked,InnoDB
performs a “semi-consistent” read, returning the latest committed version to MySQL so that MySQL can determine whether the row matches theWHERE
condition of theUPDATE
. If the row matches (must be updated), MySQL reads the row again and this timeInnoDB
either locks it or waits for a lock on it.
即使在同一事務中,每個一致的讀取也會設定和讀取自己的新快照。有關一致性讀取的資訊,請參見第15.5.2.3節“一致性非鎖定讀取”。
對於鎖定讀取(使用FOR UPDATE或FOR SHARE的SELECT),UPDATE語句和DELETE語句,InnoDB僅鎖定索引記錄,而不是它們之前的間隙,因此允許在鎖定記錄旁邊自由插入新記錄。間隙鎖定僅用於外來鍵約束檢查和重複鍵檢查。
由於禁用了間隙鎖定,因此可能會出現幻像問題,因為其他會話可以在間隙中插入新行。有關幻像的資訊,請參見第15.5.4節“幻影行”。
READ COMMITTED隔離級別僅支援基於行的二進位制日誌記錄。如果對binlog_format = MIXED使用READ COMMITTED,則伺服器會自動使用基於行的日誌記錄。
使用READ COMMITTED會產生額外的影響:
對於UPDATE或DELETE語句,InnoDB僅為其更新或刪除的行保留鎖定。 MySQL評估WHERE條件後,將釋放非匹配行的記錄鎖。這大大降低了死鎖的可能性,但它們仍然可以發生。
對於UPDATE語句,如果一行已被鎖定,InnoDB執行“半一致”讀取,將最新提交的版本返回給MySQL,以便MySQL可以確定該行是否與UPDATE的WHERE條件匹配。如果行匹配(必須更新),MySQL再次讀取該行,這次InnoDB將其鎖定或等待鎖定。
請考慮以下示例,從此表開始:
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;
在這種情況下,表沒有索引,因此搜尋和索引掃描使用隱藏的聚簇索引進行記錄鎖定(請參見第15.8.2.1節“聚簇和二級索引”)而不是索引列。
假設一個會話使用以下語句執行 :
# Session A
START TRANSACTION;
UPDATE t SET b = 5 WHERE b = 3;
假設第二個會話在第一個會話之後執行以下語句來UPDATE
:
# Session B
UPDATE t SET b = 4 WHERE b = 2;
當InnoDB
執行每個 UPDATE
,它首先獲取每行的獨佔鎖,然後確定是否修改它。如果InnoDB
不修改行,則釋放鎖。否則, InnoDB
保留鎖定直到事務結束。這會影響事務處理,如下所示。
使用預設REPEATABLE READ
隔離級別時,第一個UPDATE
在它讀取的每一行上獲取一個x鎖定,並且不釋放它們中的任何一個:
x-lock(1,2); retain x-lock
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); retain x-lock
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); retain x-lock
第二個UPDATE
塊一旦嘗試獲取任何鎖(因為第一次更新已保留所有行上的鎖),並且在第一次UPDATE
提交或回滾之前不會繼續:
x-lock(1,2); block and wait for first UPDATE to commit or roll back
如果使用READ COMMITTED級別
,則第一個UPDATE
在它讀取的每一行上獲取一個x-lock,並釋放那些它不修改的行:
x-lock(1,2); unlock(1,2)
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); unlock(3,2)
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); unlock(5,2)
對於第二個UPDATE
, InnoDB
執行 “ 半一致 ”讀取,返回它讀取到MySQL的每一行的最新提交版本,以便MySQL可以確定該行是否符合 WHERE
條件 :
x-lock(1,2); update(1,2) to (1,4); retain x-lock
x-lock(2,3); unlock(2,3)
x-lock(3,2); update(3,2) to (3,4); retain x-lock
x-lock(4,3); unlock(4,3)
x-lock(5,2); update(5,2) to (5,4); retain x-lock
但是,如果WHERE
條件包含索引列並InnoDB
使用索引,則在獲取和保留記錄鎖時僅考慮索引列。在下面的示例中,第一個 UPDATE
採用並保留每行上的x鎖定,其中b = 2.第二個 UPDATE
阻止它嘗試獲取相同記錄上的x鎖定,因為它還使用在b列上定義的索引。
CREATE TABLE t (a INT NOT NULL, b INT, c INT, INDEX (b)) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2,3),(2,2,4);
COMMIT;
# Session A
START TRANSACTION;
UPDATE t SET b = 3 WHERE b = 2 AND c = 3;
# Session B
UPDATE t SET b = 4 WHERE b = 2 AND c = 4;
(後面這個例子 有點。。。拗口 獨佔鎖應該是常說的排他鎖)
READ UNCOMMITTED
SELECT
statements are performed in a nonlocking fashion, but a possible earlier version of a row might be used. Thus, using this isolation level, such reads are not consistent. This is also called adirty read. Otherwise, this isolation level works like READ COMMITTED
.
SELECT語句以非鎖定方式執行,但可能會使用行的早期版本。 因此,使用此隔離級別,此類讀取不一致。 這也稱為髒讀。 否則,此隔離級別與READ COMMITTED類似。
SERIALIZABLE
This level is like REPEATABLE READ
, but InnoDB
implicitly converts all plain SELECT
statements to SELECT ... FOR SHARE
if autocommit
is disabled. If autocommit
is enabled, theSELECT
is its own transaction. It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions. (To force a plain SELECT
to block if other transactions have modified the selected rows, disable autocommit
.)
這個級別就像REPEATABLE READ,但InnoDB隱式地將所有普通SELECT語句轉換為SELECT ... FOR SHARE如果禁用自動提交。 如果啟用了自動提交,則SOLEL是其自己的事務。 因此,已知它是隻讀的,並且如果作為一致(非鎖定)讀取執行則可以序列化,並且不需要阻止其他事務。 (要強制普通SELECT阻止其他事務已修改所選行,請禁用自動提交。)