溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL事務(wù)與鎖的知識點(diǎn)總結(jié)

發(fā)布時間:2021-08-24 11:59:30 來源:億速云 閱讀:171 作者:chen 欄目:MySQL數(shù)據(jù)庫

這篇文章主要介紹“MySQL事務(wù)與鎖的知識點(diǎn)總結(jié)”,在日常操作中,相信很多人在MySQL事務(wù)與鎖的知識點(diǎn)總結(jié)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”MySQL事務(wù)與鎖的知識點(diǎn)總結(jié)”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

MySQL事務(wù)與鎖

1.         事務(wù)與鎖

1.1.        事務(wù)

事務(wù)是一組數(shù)據(jù)操作執(zhí)行步驟,這些步驟被視為一個工作單元,用于對多個語句進(jìn)行分組,可以在多個客戶機(jī)并發(fā)訪問同一個表中的數(shù)據(jù)時使用;所有步驟都成功或都失敗,如果所有步驟正常,則執(zhí)行,如果步驟出現(xiàn)錯誤或不完整,則取消;事務(wù)遵從 ACID。

通過事務(wù),您可以將一個或多個 SQL 語句作為一個工作單元來執(zhí)行,這樣,所有語句或者都成功,或者都失敗。在與其他任何事務(wù)執(zhí)行的工作隔離的情況下,可能會出現(xiàn)這種情況。如果所有語句都成功,則可以提交該事務(wù),以便在數(shù)據(jù)庫中永久記錄其效果。如果在事務(wù)期間出現(xiàn)錯誤,則可以回滾以取消它。此前已在該事務(wù)中執(zhí)行的任何語句將被撤消,從而使數(shù)據(jù)庫保持開始該事務(wù)之前的狀態(tài)。

注:在 MySQL 中,只有那些使用事務(wù)存儲引擎(如 InnoDB)的表才支持事務(wù)。這些語句不會對非事務(wù)存儲引擎所管理的表產(chǎn)生任何明顯影響。

MySQL事務(wù)遵從ACID:

? Atomic(原子性):所有語句作為一個單元全部成功執(zhí)行或全部取消。

? Consistent(一致性):如果數(shù)據(jù)庫在事務(wù)開始時處于一致狀態(tài),則在執(zhí)行該事務(wù)期間將保留一致狀態(tài)。

? Isolated(隔離性):事務(wù)之間不相互影響。

? Durable(持久性):事務(wù)成功完成后,所做的所有更改都會準(zhǔn)確地記錄在數(shù)據(jù)庫中。所做的更改不會丟失

1.1.1         事務(wù)SQL 控制語句

? START TRANSACTION(或BEGIN):顯式開始一個新事務(wù)

? SAVEPOINT:分配事務(wù)過程中的一個位置,以供將來引用

? COMMIT:永久記錄當(dāng)前事務(wù)所做的更改

? ROLLBACK:取消當(dāng)前事務(wù)所做的更改

? ROLLBACK TO SAVEPOINT:取消在savepoint 之后執(zhí)行的更改

? RELEASE SAVEPOINT:刪除savepoint 標(biāo)識符

? SET AUTOCOMMIT:為當(dāng)前連接禁用或啟用默認(rèn)autocommit 模式

1.1.2         AUTOCOMMIT 模式

如何設(shè)置 AUTOCOMMIT 模式?jīng)Q定了如何以及何時開始新事務(wù)。默認(rèn)情況下,AUTOCOMMIT 處于全局啟用狀態(tài),這意味著會強(qiáng)制每個 SQL 語句隱式開始一個新事務(wù)??梢酝ㄟ^一個配置文件全局禁用 AUTOCOMMIT,也可以通過設(shè)置 autocommit 變量為每個會話禁用它。啟用 AUTOCOMMIT 會限制每個語句,并進(jìn)而影響其自身事務(wù)中的事務(wù)表。這樣可以有效地防止在一個事務(wù)中執(zhí)行多個語句。這意味著,您將無法通過 COMMIT 或 ROLLBACK 作為一個單元提交或回滾多個語句。有時,會將這種情況誤認(rèn)為根本沒有事務(wù)。但是,情況并非如此。啟用 AUTOCOMMIT 后,每個語句仍會以原子方式執(zhí)行。例如,通過在插入多個行時比較違反約束限制的效果,便可看出啟用 AUTOCOMMIT 和根本不具有事務(wù)之間的差別。在非事務(wù)表(如 MyISAM)中,一旦發(fā)生錯誤,語句就會終止,已經(jīng)插入的行會保留在該表中。而對于 InnoDB 表,已經(jīng)插入的所有行都會從該表中刪除,從而不會產(chǎn)生任何實(shí)際影響。

AUTOCOMMIT確定開始新事務(wù)的方式和時間;默認(rèn)情況下, AUTOCOMMIT 模式處于啟用狀態(tài):作為一個事務(wù)隱式提交每個語句;

在my.cnf中將 AUTOCOMMIT 模式設(shè)置為 0,或者SET GLOBAL AUTOCOMMIT=0;SET SESSION AUTOCOMMIT=0; SET @@AUTOCOMMIT :=0; 則禁用 AUTOCOMMIT,事務(wù)會跨越多個語句,需要使用 COMMIT 或 ROLLBACK 結(jié)束事務(wù);

使用 SELECT 檢查 AUTOCOMMIT 設(shè)置:

SELECT @@AUTOCOMMIT;

1.1.3         隱式提交

COMMIT 語句始終會顯式提交當(dāng)前事務(wù)。其他事務(wù)控制語句(例如,本幻燈片列出的語句)還具有隱式提交當(dāng)前事務(wù)的作用。除了這些事務(wù)控制語句之外,其他類型的語句可能也具有隱式提交并進(jìn)而終止)當(dāng)前事務(wù)的作用。這些語句的行為就像在執(zhí)行實(shí)際語句之前發(fā)出 COMMIT 一樣。此外,這些語句本身并非事務(wù)語句,也就是說,如果成功,則無法回滾。通常,數(shù)據(jù)定義語句、據(jù)訪問和用戶管理語句以及Lock語句具有這種效果。

注:有很多例外情況,而且這些語句并非都能在所有版本的服務(wù)器上導(dǎo)致隱式提交。但是,建議將所有非 DML 語句都視為可導(dǎo)致隱式提交。有關(guān)導(dǎo)致隱式提交的完整語句列表,請參閱《MySQL 參考手冊》:http://dev.mysql.com/doc/refman/5.6/en/implicit-commit.html

隱式提交會終止當(dāng)前事務(wù)。用于隱式提交的 SQL 語句:

l  START TRANSACTION

l  SET AUTOCOMMIT = 1

導(dǎo)致提交的非事務(wù)語句:

l  數(shù)據(jù)定義語句(ALTER、 CREATE 和 DROP)

l  管理語句(GRANT、 REVOKE 和 SET PASSWORD)

l  Lock語句(LOCK TABLES 和 UNLOCK TABLES)

導(dǎo)致隱式提交的語句示例:

Mysql>TRUNCATE TABLE

Mysql>LOAD DATA INFILE

1.1.4         事務(wù)存儲引擎

使用 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

...

要確保事務(wù)存儲引擎已編譯到 MySQL 服務(wù)器中,并且可以在運(yùn)行時使用,可使用 SHOW ENGINES 語句。Support 列中的值為 YES 或 NO,用于指示該引擎是否可以使用。如果該值為DISABLED則表示該引擎存在,但已關(guān)閉。值 DEFAULT 用于指示服務(wù)器在默認(rèn)情況下使用的存儲引擎。指定為 DEFAULT 的引擎應(yīng)視為可用。 Transactions、 XA 和Savepoints 列用于指示該存儲引擎是否支持這些功能。

1.2.        事務(wù)隔離級別

1.2.1         隔離級別介紹

如果一個客戶機(jī)的事務(wù)更改了數(shù)據(jù),其他客戶機(jī)的事務(wù)是應(yīng)發(fā)現(xiàn)這些更改還是應(yīng)與其隔離,事務(wù)隔離級別可以確定同時進(jìn)行的事務(wù)在訪問相同數(shù)據(jù)時彼此交互的方式。使用存儲引擎可實(shí)現(xiàn)隔離級別。隔離級別選項(xiàng)在不同的數(shù)據(jù)庫服務(wù)器之間是不一樣的,因此, InnoDB 所實(shí)現(xiàn)的級別可能與其他數(shù)據(jù)庫系統(tǒng)所實(shí)現(xiàn)的級別并不完全對應(yīng)。InnoDB 可實(shí)現(xiàn)四種隔離級別,用于控制事務(wù)所做的更改在多大程度上可由其他同時進(jìn)行的事務(wù)注意到。四種隔離級別如下:

l  READ UNCOMMITTED:允許事務(wù)查看其他事務(wù)所進(jìn)行的未提交更改;允許發(fā)生“臟” 讀、不可重復(fù)讀和虛讀。

l  READ COMMITTED:允許事務(wù)查看其他事務(wù)所進(jìn)行的已提交更改;允許發(fā)生不可重復(fù)讀和虛讀。未提交的更改仍不可見。

l  REPEATABLE READ:確保每個事務(wù)的 SELECT 輸出一致,InnoDB 的默認(rèn)級別;無論其他事務(wù)所做的更改是否已提交,兩次都會獲得相同的結(jié)果。換句話說,也就是不同的事務(wù)會對相同的數(shù)據(jù)產(chǎn)生一致的結(jié)果。

l  SERIALIZABLE:將一個事務(wù)的結(jié)果與其他事務(wù)完全隔離;與 REPEATABLE READ 類似,但其限制性更強(qiáng),即一個事務(wù)所選的行不能由其他事務(wù)更改,直到第一個事務(wù)完成為止。

                 MySQL事務(wù)與鎖的知識點(diǎn)總結(jié)                            

1.2.2         設(shè)置隔離級別

系統(tǒng)默認(rèn)事務(wù)級別為:repeatable-read

方法一、 服務(wù)器啟動時設(shè)置級別。

–  在mysqld 命令中使用--transaction-isolation選項(xiàng)。

–  在配置文件中設(shè)置transaction-isolation:

[mysqld]

transaction-isolation = <isolation_level>

在配置文件中或在命令行上將<isolation_level> 值設(shè)置為:

l  READ-UNCOMMITTED

l  READ-COMMITTED

l  REPEATABLE-READ

l  SERIALIZABLE

方法二、使用SET TRANSACTION ISOLATION LEVEL 語句為正在運(yùn)行的服務(wù)器設(shè)置。

– 語法示例:

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> 值設(shè)置為:

l  READ UNCOMMITTED

l  READ COMMITTED

l  REPEATABLE READ

l  SERIALIZABLE。

此事務(wù)級別可以全局設(shè)置,也可以按會話設(shè)置。如果沒有顯式指定,則事務(wù)隔離級別將按會話進(jìn)行設(shè)置。例如,以下語句會將當(dāng)前mysql 會話的隔離級別設(shè)置為READ COMITTED:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

該語句相當(dāng)于:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

要設(shè)置所有后續(xù)mysql 連接的默認(rèn)級別,請使用GLOBAL 關(guān)鍵字,而不是SESSION:

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

注:設(shè)置的全局默認(rèn)事務(wù)隔離級別適用于從設(shè)置時起所有新建立的客戶機(jī)連接?,F(xiàn)有連接不受影響。

方法三、SET GLOBAL TX_ISOLATION

         需要 SUPER 權(quán)限

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 使用多線程體系結(jié)構(gòu),多個客戶機(jī)訪問一個表時會出現(xiàn)問題,有必要對客戶機(jī)進(jìn)行協(xié)調(diào);Lock是一種防止出現(xiàn)并發(fā)問題的機(jī)制,由服務(wù)器管理,Lock供一個客戶機(jī)訪問,限制其他客戶機(jī)訪問,Lock類型:共享鎖、互斥鎖

Lock機(jī)制可以防止因多個客戶機(jī)同時訪問數(shù)據(jù)而出現(xiàn)的問題。該機(jī)制會以某個客戶機(jī)的身份Lock數(shù)據(jù),以限制其他客戶機(jī)訪問該數(shù)據(jù),直到釋放Lock為止。該Lock允許持有鎖的客戶機(jī)訪問數(shù)據(jù),而限制與之爭用訪問權(quán)限的其他客戶機(jī)可以執(zhí)行的操作。Lock機(jī)制的結(jié)果是,將對數(shù)據(jù)的訪問序列化,這樣,在多個客戶機(jī)要執(zhí)行相互沖突的操作時,每個客戶機(jī)都必須輪流等待。并非所有類型的并發(fā)訪問都會產(chǎn)生沖突,因此,允許客戶機(jī)訪問數(shù)據(jù)所需的Lock類型取決于該客戶機(jī)是希望讀取還是希望寫入:

? 如果某個客戶機(jī)希望讀取數(shù)據(jù),則希望讀取相同數(shù)據(jù)的其他客戶機(jī)不會產(chǎn)生沖突,它們可以同時進(jìn)行讀取。但是,如果另一個客戶機(jī)希望寫入(修改)數(shù)據(jù),則它必須等待,直到讀取完成為止。

? 如果某個客戶機(jī)希望寫入數(shù)據(jù),則所有其他客戶機(jī)都必須等待,直到寫入完成,而無論這些客戶機(jī)是想讀取還是想寫入。

讀取器必須阻止寫入器,但不能阻止其他讀取器。寫入器必須同時阻止讀取器和寫入器。通過讀取鎖和寫入鎖,可以強(qiáng)制實(shí)施這些限制。利用Lock,可以使客戶機(jī)進(jìn)入等待狀態(tài),直到能夠安全地訪問數(shù)據(jù)為止。借助這種方式,Lock可以禁止并發(fā)進(jìn)行相互沖突的更改并禁止讀取正在更改的數(shù)據(jù),從而可以防止數(shù)據(jù)損壞。

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 子句: 共享鎖,也就是說,雖然任何其他事務(wù)都無法獲得互斥鎖,但其他事務(wù)可以同時使用共享鎖。由于正常讀取不會Lock任何內(nèi)容,因此它們不會受Lock的影響。

? FOR UPDATE 子句: 使用互斥鎖來Lock選定的每一行,以防止其他對象獲得這些行上的任何鎖,但允許讀取這些行。

在 REPEATABLE READ 隔離級別中,可以將 LOCK IN SHARE MODE 添加到 SELECT操作中,這樣,如果其他事務(wù)想修改選定行,則它們必須等待當(dāng)前事務(wù)完成。這一點(diǎn)與SERIALIZABLE 隔離級別的工作方式類似,對于該隔離級別, InnoDB 會隱式將 LOCK IN SHARE MODE 添加到 SELECT 語句中,而不會包含任何顯式Lock修飾符。如果選擇了在未提交的事務(wù)中修改的行,則會Lock SELECT,直到該事務(wù)提交為止。

1.3.2         死鎖

如果多個事務(wù)都需要訪問數(shù)據(jù),而另一個事務(wù)已經(jīng)以互斥方式Lock該數(shù)據(jù),則會發(fā)生死鎖。在兩個或更多事務(wù)之間發(fā)生循環(huán)依賴性時。例如, T1 等待由 T2 Lock的資源,而 T2 等待由 T3 Lock的資源,同時 T3 又等待由 T1 Lock的資源。InnoDB 會檢測并中止(回滾)其中一個事務(wù),并允許另一個事務(wù)完成。

死鎖是事務(wù)數(shù)據(jù)庫中的一個經(jīng)典問題,它們并不具有危害性,除非它們經(jīng)常發(fā)生,從而使您根本無法運(yùn)行某些事務(wù)。死鎖發(fā)生的條件如下:

? 事務(wù)獲得多個表上的Lock,但順序相反。

? 諸如 UPDATE 或 SELECT ... FOR UPDATE 等語句Lock了一系列索引記錄和間隙,其中,每個事務(wù)因計(jì)時問題而僅獲取了部分Lock。

? 存在多個事務(wù),其中每個事務(wù)都在等待另一個事務(wù)完成,從而構(gòu)成一個循環(huán)。例如,T1 正在等待 T2, T2 正在等待 T3, T3 正在等待 T1。

如果 InnoDB 對某個事務(wù)執(zhí)行完整回滾,則該事務(wù)所設(shè)置的所有Lock都會被釋放。但是,如果因出現(xiàn)錯誤而僅回滾了一個 SQL 語句,則該語句所設(shè)置的某些Lock可能會保留。發(fā)生此問題的原因是, InnoDB 存儲行鎖的格式使它此后無法識別鎖和語句之間的對應(yīng)關(guān)系。如果 SELECT 語句在事務(wù)中調(diào)用一個存儲函數(shù),而該函數(shù)中的一個語句出現(xiàn)錯誤,則該語句將回滾。同時,如果此后執(zhí)行 ROLLBACK,則整個事務(wù)將回滾。

有關(guān) InnoDB 死鎖的更多信息,請參閱《MySQL 參考手冊》:

http://dev.mysql.com/doc/refman/5.6/en/innodb-deadlock-detection.html。

事務(wù)示例:死鎖

會話 1

會話 2

s1> START   TRANSACTION;
  s1> UPDATE Country
  -> SET Name = 'Sakila'
  -> WHERE Code = 'SWE';



s2> START   TRANSACTION;
  s2> UPDATE Country
  -> SET Name = 'World Cup Winner'
  -> WHERE Code = 'ITA';

s1> DELETE   FROM Country
  -> WHERE Code = 'ITA';



s2> UPDATE   Country
  -> SET population=1
  -> WHERE Code = 'SWE';
  ERROR 1213 (40001): Deadlock
  found when trying to get lock;
  try restarting transaction

Query OK, 1 row   affected (0.0 sec)


第一條 DELETE 語句在等待鎖時掛起。在執(zhí)行 UPDATE 語句期間,由于兩個會話出現(xiàn)沖突,因此,在會話 2 中檢測到死鎖。 UPDATE 將被中止,從而允許會話 1 中的 DELETE完成。

1.3.3         隱式鎖

MySQL 服務(wù)器會根據(jù)所發(fā)出的命令以及所使用的存儲引擎來Lock表(或行):

操作

InnoDB

MyISAM

SELECT

無鎖*

表級別共享鎖

UPDATE/DELETE

行級別互斥鎖

表級別互斥鎖

ALTER TABLE

表級別共享鎖

表級別共享鎖

* 無鎖,除非使用了 SERIALIZABLE 級別、 LOCK IN SHARE MODE 或 FOR UPDATE

InnoDB 表會使用行級別Lock,以使多個會話和應(yīng)用程序能夠同時讀取和寫入同一個表,而不會相互等待,也不會產(chǎn)生不一致的結(jié)果。對于此存儲引擎,請避免使用 LOCK TABLES 語句;它不會提供任何額外的保護(hù),卻會減少并發(fā)性。

利用自動行級別Lock,可以使這些表適用于存儲最重要數(shù)據(jù)的最繁忙數(shù)據(jù)庫,同時還能簡化應(yīng)用邏輯,因?yàn)槟鸁o需對表進(jìn)行Lock和解鎖。這樣, InnoDB 存儲引擎就成為MySQL 5.6 中的默認(rèn)設(shè)置

到此,關(guān)于“MySQL事務(wù)與鎖的知識點(diǎn)總結(jié)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI