您好,登錄后才能下訂單哦!
這篇文章主要介紹“MySQL事務與鎖的知識點總結”,在日常操作中,相信很多人在MySQL事務與鎖的知識點總結問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”MySQL事務與鎖的知識點總結”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
1. 事務與鎖
1.1. 事務
事務是一組數據操作執行步驟,這些步驟被視為一個工作單元,用于對多個語句進行分組,可以在多個客戶機并發訪問同一個表中的數據時使用;所有步驟都成功或都失敗,如果所有步驟正常,則執行,如果步驟出現錯誤或不完整,則取消;事務遵從 ACID。
通過事務,您可以將一個或多個 SQL 語句作為一個工作單元來執行,這樣,所有語句或者都成功,或者都失敗。在與其他任何事務執行的工作隔離的情況下,可能會出現這種情況。如果所有語句都成功,則可以提交該事務,以便在數據庫中永久記錄其效果。如果在事務期間出現錯誤,則可以回滾以取消它。此前已在該事務中執行的任何語句將被撤消,從而使數據庫保持開始該事務之前的狀態。
注:在 MySQL 中,只有那些使用事務存儲引擎(如 InnoDB)的表才支持事務。這些語句不會對非事務存儲引擎所管理的表產生任何明顯影響。
MySQL事務遵從ACID:
? Atomic(原子性):所有語句作為一個單元全部成功執行或全部取消。
? Consistent(一致性):如果數據庫在事務開始時處于一致狀態,則在執行該事務期間將保留一致狀態。
? Isolated(隔離性):事務之間不相互影響。
? Durable(持久性):事務成功完成后,所做的所有更改都會準確地記錄在數據庫中。所做的更改不會丟失
1.1.1 事務SQL 控制語句
? START TRANSACTION(或BEGIN):顯式開始一個新事務
? SAVEPOINT:分配事務過程中的一個位置,以供將來引用
? COMMIT:永久記錄當前事務所做的更改
? ROLLBACK:取消當前事務所做的更改
? ROLLBACK TO SAVEPOINT:取消在savepoint 之后執行的更改
? RELEASE SAVEPOINT:刪除savepoint 標識符
? SET AUTOCOMMIT:為當前連接禁用或啟用默認autocommit 模式
1.1.2 AUTOCOMMIT 模式
如何設置 AUTOCOMMIT 模式決定了如何以及何時開始新事務。默認情況下,AUTOCOMMIT 處于全局啟用狀態,這意味著會強制每個 SQL 語句隱式開始一個新事務。可以通過一個配置文件全局禁用 AUTOCOMMIT,也可以通過設置 autocommit 變量為每個會話禁用它。啟用 AUTOCOMMIT 會限制每個語句,并進而影響其自身事務中的事務表。這樣可以有效地防止在一個事務中執行多個語句。這意味著,您將無法通過 COMMIT 或 ROLLBACK 作為一個單元提交或回滾多個語句。有時,會將這種情況誤認為根本沒有事務。但是,情況并非如此。啟用 AUTOCOMMIT 后,每個語句仍會以原子方式執行。例如,通過在插入多個行時比較違反約束限制的效果,便可看出啟用 AUTOCOMMIT 和根本不具有事務之間的差別。在非事務表(如 MyISAM)中,一旦發生錯誤,語句就會終止,已經插入的行會保留在該表中。而對于 InnoDB 表,已經插入的所有行都會從該表中刪除,從而不會產生任何實際影響。
AUTOCOMMIT確定開始新事務的方式和時間;默認情況下, AUTOCOMMIT 模式處于啟用狀態:作為一個事務隱式提交每個語句;
在my.cnf中將 AUTOCOMMIT 模式設置為 0,或者SET GLOBAL AUTOCOMMIT=0;SET SESSION AUTOCOMMIT=0; SET @@AUTOCOMMIT :=0; 則禁用 AUTOCOMMIT,事務會跨越多個語句,需要使用 COMMIT 或 ROLLBACK 結束事務;
使用 SELECT 檢查 AUTOCOMMIT 設置:
SELECT @@AUTOCOMMIT;
1.1.3 隱式提交
COMMIT 語句始終會顯式提交當前事務。其他事務控制語句(例如,本幻燈片列出的語句)還具有隱式提交當前事務的作用。除了這些事務控制語句之外,其他類型的語句可能也具有隱式提交并進而終止)當前事務的作用。這些語句的行為就像在執行實際語句之前發出 COMMIT 一樣。此外,這些語句本身并非事務語句,也就是說,如果成功,則無法回滾。通常,數據定義語句、據訪問和用戶管理語句以及Lock語句具有這種效果。
注:有很多例外情況,而且這些語句并非都能在所有版本的服務器上導致隱式提交。但是,建議將所有非 DML 語句都視為可導致隱式提交。有關導致隱式提交的完整語句列表,請參閱《MySQL 參考手冊》:http://dev.mysql.com/doc/refman/5.6/en/implicit-commit.html
隱式提交會終止當前事務。用于隱式提交的 SQL 語句:
l START TRANSACTION
l SET AUTOCOMMIT = 1
導致提交的非事務語句:
l 數據定義語句(ALTER、 CREATE 和 DROP)
l 管理語句(GRANT、 REVOKE 和 SET PASSWORD)
l Lock語句(LOCK TABLES 和 UNLOCK TABLES)
導致隱式提交的語句示例:
Mysql>TRUNCATE TABLE
Mysql>LOAD DATA INFILE
1.1.4 事務存儲引擎
使用 SHOW ENGINES 列出引擎特征:
mysql> SHOW ENGINES\G
********************* 2. row *********************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking,
and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
********************* 1. row *********************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
...
要確保事務存儲引擎已編譯到 MySQL 服務器中,并且可以在運行時使用,可使用 SHOW ENGINES 語句。Support 列中的值為 YES 或 NO,用于指示該引擎是否可以使用。如果該值為DISABLED則表示該引擎存在,但已關閉。值 DEFAULT 用于指示服務器在默認情況下使用的存儲引擎。指定為 DEFAULT 的引擎應視為可用。 Transactions、 XA 和Savepoints 列用于指示該存儲引擎是否支持這些功能。
1.2. 事務隔離級別
1.2.1 隔離級別介紹
如果一個客戶機的事務更改了數據,其他客戶機的事務是應發現這些更改還是應與其隔離,事務隔離級別可以確定同時進行的事務在訪問相同數據時彼此交互的方式。使用存儲引擎可實現隔離級別。隔離級別選項在不同的數據庫服務器之間是不一樣的,因此, InnoDB 所實現的級別可能與其他數據庫系統所實現的級別并不完全對應。InnoDB 可實現四種隔離級別,用于控制事務所做的更改在多大程度上可由其他同時進行的事務注意到。四種隔離級別如下:
l READ UNCOMMITTED:允許事務查看其他事務所進行的未提交更改;允許發生“臟” 讀、不可重復讀和虛讀。
l READ COMMITTED:允許事務查看其他事務所進行的已提交更改;允許發生不可重復讀和虛讀。未提交的更改仍不可見。
l REPEATABLE READ:確保每個事務的 SELECT 輸出一致,InnoDB 的默認級別;無論其他事務所做的更改是否已提交,兩次都會獲得相同的結果。換句話說,也就是不同的事務會對相同的數據產生一致的結果。
l SERIALIZABLE:將一個事務的結果與其他事務完全隔離;與 REPEATABLE READ 類似,但其限制性更強,即一個事務所選的行不能由其他事務更改,直到第一個事務完成為止。
1.2.2 設置隔離級別
系統默認事務級別為:repeatable-read
方法一、 服務器啟動時設置級別。
– 在mysqld 命令中使用--transaction-isolation選項。
– 在配置文件中設置transaction-isolation:
[mysqld]
transaction-isolation = <isolation_level>
在配置文件中或在命令行上將<isolation_level> 值設置為:
l READ-UNCOMMITTED
l READ-COMMITTED
l REPEATABLE-READ
l SERIALIZABLE
方法二、使用SET TRANSACTION ISOLATION LEVEL 語句為正在運行的服務器設置。
– 語法示例:
SET GLOBAL TRANSACTION ISOLATION LEVEL <isolation_level>;
SET SESSION TRANSACTION ISOLATION LEVEL <isolation_level>;
SET TRANSACTION ISOLATION LEVEL <isolation_level>;
對于SET TRANSACTION ISOLATION LEVEL 語句,將<isolation_level> 值設置為:
l READ UNCOMMITTED
l READ COMMITTED
l REPEATABLE READ
l SERIALIZABLE。
此事務級別可以全局設置,也可以按會話設置。如果沒有顯式指定,則事務隔離級別將按會話進行設置。例如,以下語句會將當前mysql 會話的隔離級別設置為READ COMITTED:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
該語句相當于:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
要設置所有后續mysql 連接的默認級別,請使用GLOBAL 關鍵字,而不是SESSION:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
注:設置的全局默認事務隔離級別適用于從設置時起所有新建立的客戶機連接。現有連接不受影響。
方法三、SET GLOBAL TX_ISOLATION
需要 SUPER 權限
Mysql>set global tx_isolation=’ READ-COMMITTED’
Mysql>select @@tx_isolation;
Mysql>show variables like ‘tx_isolation’;
transaction_isolation MySQL 5.7.20引入,目的是替換即將棄用的tx_isolation(MySQL 8.0);
(root@localhost) [information_schema]> show variables like '%isolat%';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
| tx_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
transaction_isolation was added in MySQL 5.7.20 as an alias for tx_isolation, which is now deprecated and is removed in MySQL 8.0. Applications should be adjusted to use transaction_isolation in preference to tx_isolation.
1.3. 鎖概念
MySQL 使用多線程體系結構,多個客戶機訪問一個表時會出現問題,有必要對客戶機進行協調;Lock是一種防止出現并發問題的機制,由服務器管理,Lock供一個客戶機訪問,限制其他客戶機訪問,Lock類型:共享鎖、互斥鎖
Lock機制可以防止因多個客戶機同時訪問數據而出現的問題。該機制會以某個客戶機的身份Lock數據,以限制其他客戶機訪問該數據,直到釋放Lock為止。該Lock允許持有鎖的客戶機訪問數據,而限制與之爭用訪問權限的其他客戶機可以執行的操作。Lock機制的結果是,將對數據的訪問序列化,這樣,在多個客戶機要執行相互沖突的操作時,每個客戶機都必須輪流等待。并非所有類型的并發訪問都會產生沖突,因此,允許客戶機訪問數據所需的Lock類型取決于該客戶機是希望讀取還是希望寫入:
? 如果某個客戶機希望讀取數據,則希望讀取相同數據的其他客戶機不會產生沖突,它們可以同時進行讀取。但是,如果另一個客戶機希望寫入(修改)數據,則它必須等待,直到讀取完成為止。
? 如果某個客戶機希望寫入數據,則所有其他客戶機都必須等待,直到寫入完成,而無論這些客戶機是想讀取還是想寫入。
讀取器必須阻止寫入器,但不能阻止其他讀取器。寫入器必須同時阻止讀取器和寫入器。通過讀取鎖和寫入鎖,可以強制實施這些限制。利用Lock,可以使客戶機進入等待狀態,直到能夠安全地訪問數據為止。借助這種方式,Lock可以禁止并發進行相互沖突的更改并禁止讀取正在更改的數據,從而可以防止數據損壞。
1.3.1 顯式行鎖
InnoDB 支持兩種類型的行Lock:
? LOCK IN SHARE MODE:使用共享鎖Lock每一行
SELECT * FROM Country WHERE Code='AUS' LOCK IN SHARE MODE\G
? FOR UPDATE:使用互斥鎖Lock每一行
SELECT counter_field INTO @@counter_field
FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field =
@@counter_field + 1;
InnoDB 支持兩種Lock修飾符,這兩種修飾符可以添加到 SELECT 語句的末尾:
? LOCK IN SHARE MODE 子句: 共享鎖,也就是說,雖然任何其他事務都無法獲得互斥鎖,但其他事務可以同時使用共享鎖。由于正常讀取不會Lock任何內容,因此它們不會受Lock的影響。
? FOR UPDATE 子句: 使用互斥鎖來Lock選定的每一行,以防止其他對象獲得這些行上的任何鎖,但允許讀取這些行。
在 REPEATABLE READ 隔離級別中,可以將 LOCK IN SHARE MODE 添加到 SELECT操作中,這樣,如果其他事務想修改選定行,則它們必須等待當前事務完成。這一點與SERIALIZABLE 隔離級別的工作方式類似,對于該隔離級別, InnoDB 會隱式將 LOCK IN SHARE MODE 添加到 SELECT 語句中,而不會包含任何顯式Lock修飾符。如果選擇了在未提交的事務中修改的行,則會Lock SELECT,直到該事務提交為止。
1.3.2 死鎖
如果多個事務都需要訪問數據,而另一個事務已經以互斥方式Lock該數據,則會發生死鎖。在兩個或更多事務之間發生循環依賴性時。例如, T1 等待由 T2 Lock的資源,而 T2 等待由 T3 Lock的資源,同時 T3 又等待由 T1 Lock的資源。InnoDB 會檢測并中止(回滾)其中一個事務,并允許另一個事務完成。
死鎖是事務數據庫中的一個經典問題,它們并不具有危害性,除非它們經常發生,從而使您根本無法運行某些事務。死鎖發生的條件如下:
? 事務獲得多個表上的Lock,但順序相反。
? 諸如 UPDATE 或 SELECT ... FOR UPDATE 等語句Lock了一系列索引記錄和間隙,其中,每個事務因計時問題而僅獲取了部分Lock。
? 存在多個事務,其中每個事務都在等待另一個事務完成,從而構成一個循環。例如,T1 正在等待 T2, T2 正在等待 T3, T3 正在等待 T1。
如果 InnoDB 對某個事務執行完整回滾,則該事務所設置的所有Lock都會被釋放。但是,如果因出現錯誤而僅回滾了一個 SQL 語句,則該語句所設置的某些Lock可能會保留。發生此問題的原因是, InnoDB 存儲行鎖的格式使它此后無法識別鎖和語句之間的對應關系。如果 SELECT 語句在事務中調用一個存儲函數,而該函數中的一個語句出現錯誤,則該語句將回滾。同時,如果此后執行 ROLLBACK,則整個事務將回滾。
有關 InnoDB 死鎖的更多信息,請參閱《MySQL 參考手冊》:
http://dev.mysql.com/doc/refman/5.6/en/innodb-deadlock-detection.html。
事務示例:死鎖
會話 1 | 會話 2 |
s1> START TRANSACTION; | |
s2> START TRANSACTION; | |
s1> DELETE FROM Country | |
s2> UPDATE Country | |
Query OK, 1 row affected (0.0 sec) |
第一條 DELETE 語句在等待鎖時掛起。在執行 UPDATE 語句期間,由于兩個會話出現沖突,因此,在會話 2 中檢測到死鎖。 UPDATE 將被中止,從而允許會話 1 中的 DELETE完成。
1.3.3 隱式鎖
MySQL 服務器會根據所發出的命令以及所使用的存儲引擎來Lock表(或行):
操作 | InnoDB | MyISAM |
SELECT | 無鎖* | 表級別共享鎖 |
UPDATE/DELETE | 行級別互斥鎖 | 表級別互斥鎖 |
ALTER TABLE | 表級別共享鎖 | 表級別共享鎖 |
* 無鎖,除非使用了 SERIALIZABLE 級別、 LOCK IN SHARE MODE 或 FOR UPDATE
InnoDB 表會使用行級別Lock,以使多個會話和應用程序能夠同時讀取和寫入同一個表,而不會相互等待,也不會產生不一致的結果。對于此存儲引擎,請避免使用 LOCK TABLES 語句;它不會提供任何額外的保護,卻會減少并發性。
利用自動行級別Lock,可以使這些表適用于存儲最重要數據的最繁忙數據庫,同時還能簡化應用邏輯,因為您無需對表進行Lock和解鎖。這樣, InnoDB 存儲引擎就成為MySQL 5.6 中的默認設置
到此,關于“MySQL事務與鎖的知識點總結”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。