欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL中表鎖和行鎖機(jī)制淺析(源碼篇)

 更新時(shí)間:2022年11月04日 16:40:46   作者:Java白羊  
在計(jì)算機(jī)科學(xué)中,鎖是在執(zhí)行多線程時(shí)用于強(qiáng)行限制資源訪問的同步機(jī)制,即用于在并發(fā)控制中保證對互斥要求的滿足,下面這篇文章主要給大家介紹了MySQL中表鎖和行鎖機(jī)制淺析的相關(guān)資料,需要的朋友可以參考下

前言

眾所周知,MySQL的存儲引擎有MyISAM和InnoDB,鎖粒度分別是表鎖和行鎖。

后者的出現(xiàn)從某種程度上是彌補(bǔ)前者的不足,比如:MyISAM不支持事務(wù),InnoDB支持事務(wù)。表鎖雖然開銷小,鎖表快,但高并發(fā)下性能低。行鎖雖然開銷大,鎖表慢,但高并發(fā)下相比之下性能更高。事務(wù)和行鎖都是在確保數(shù)據(jù)準(zhǔn)確的基礎(chǔ)上提高并發(fā)的處理能力。下面分別進(jìn)行介紹:

行鎖

行鎖的劣勢:

  • 開銷大;
  • 加鎖慢;
  • 會出現(xiàn)死鎖

行鎖的優(yōu)勢:

  • 鎖的粒度小,發(fā)生鎖沖突的概率低;
  • 處理并發(fā)的能力強(qiáng)

加鎖的方式:

  • 自動(dòng)加鎖:對于UPDATE、DELETE和INSERT語句,InnoDB會自動(dòng)給涉及數(shù)據(jù)集加排他鎖;
  • 無鎖:對于普通SELECT語句,InnoDB不會加任何鎖;當(dāng)然我們也可以顯示的加鎖:
  • 共享鎖:select * from tableName where ... + lock in share more
  • 排他鎖:select * from tableName where ... + for update

InnoDB和MyISAM的最大不同點(diǎn)有兩個(gè):

  • InnoDB支持事務(wù)(transaction);
  • 默認(rèn)采用行級鎖。

加鎖可以保證事務(wù)的一致性,下面我們來學(xué)習(xí)一下MySQL的事務(wù)知識.

MySQL 事務(wù)屬性

事務(wù)是由一組SQL語句組成的邏輯處理單元,事務(wù)具有ACID屬性。 原子性(Atomicity):事務(wù)是一個(gè)原子操作單元。在當(dāng)時(shí)原子是不可分割的最小元素,其對數(shù)據(jù)的修改,要么全部成功,要么全部都不成功。 一致性(Consistent):事務(wù)開始到結(jié)束的時(shí)間段內(nèi),數(shù)據(jù)都必須保持一致狀態(tài)。 隔離性(Isolation):數(shù)據(jù)庫系統(tǒng)提供一定的隔離機(jī)制,保證事務(wù)在不受外部并發(fā)操作影響的"獨(dú)立"環(huán)境執(zhí)行。 持久性(Durable):事務(wù)完成后,它對于數(shù)據(jù)的修改是永久性的,即使出現(xiàn)系統(tǒng)故障也能夠保持。

事務(wù)常見問題

更新丟失(Lost Update) 原因:當(dāng)多個(gè)事務(wù)選擇同一行操作,并且都是基于最初選定的值,由于每個(gè)事務(wù)都不知道其他事務(wù)的存在,就會發(fā)生更新覆蓋的問題。類比github提交沖突。

臟讀(Dirty Reads) 原因:事務(wù)A讀取了事務(wù)B已經(jīng)修改但尚未提交的數(shù)據(jù)。若事務(wù)B回滾數(shù)據(jù),事務(wù)A的數(shù)據(jù)存在不一致性的問題。

不可重復(fù)讀(Non-Repeatable Reads) 原因:事務(wù)A第一次讀取最初數(shù)據(jù),第二次讀取事務(wù)B已經(jīng)提交的修改或刪除數(shù)據(jù)。導(dǎo)致兩次讀取數(shù)據(jù)不一致。不符合事務(wù)的隔離性。

幻讀(Phantom Reads) 原因:事務(wù)A根據(jù)相同條件第二次查詢到事務(wù)B提交的新增數(shù)據(jù),兩次數(shù)據(jù)結(jié)果集不一致。不符合事務(wù)的隔離性。

幻讀和臟讀有點(diǎn)類似 臟讀是事務(wù)B里面修改了數(shù)據(jù), 幻讀是事務(wù)B里面新增了數(shù)據(jù)。

事務(wù)的隔離級別

數(shù)據(jù)庫的事務(wù)隔離越嚴(yán)格,并發(fā)副作用越小,但付出的代價(jià)也就越大。這是因?yàn)槭聞?wù)隔離實(shí)質(zhì)上是將事務(wù)在一定程度上"串行"進(jìn)行,這顯然與"并發(fā)"是矛盾的。根據(jù)自己的業(yè)務(wù)邏輯,權(quán)衡能接受的最大副作用。從而平衡了"隔離" 和 "并發(fā)"的問題。MySQL默認(rèn)隔離級別是可重復(fù)讀。 臟讀,不可重復(fù)讀,幻讀,其實(shí)都是數(shù)據(jù)庫讀一致性問題,必須由數(shù)據(jù)庫提供一定的事務(wù)隔離機(jī)制來解決。

+------------------------------+---------------------+--------------+--------------+--------------+
| 隔離級別                      | 讀數(shù)據(jù)一致性         | 臟讀         | 不可重復(fù) 讀   | 幻讀         |
+------------------------------+---------------------+--------------+--------------+--------------+
| 未提交讀(Read uncommitted)    | 最低級別            | 是            | 是           | 是           | 
+------------------------------+---------------------+--------------+--------------+--------------+
| 已提交讀(Read committed)      | 語句級              | 否           | 是           | 是           |
+------------------------------+---------------------+--------------+--------------+--------------+
| 可重復(fù)讀(Repeatable read)     | 事務(wù)級              | 否           | 否           | 是           |
+------------------------------+---------------------+--------------+--------------+--------------+
| 可序列化(Serializable)        | 最高級別,事務(wù)級     | 否           | 否           | 否           |
+------------------------------+---------------------+--------------+--------------+--------------+

查看當(dāng)前數(shù)據(jù)庫的事務(wù)隔離級別:show variables like 'tx_isolation';

mysql> show variables like 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+

間隙鎖

當(dāng)我們用范圍條件檢索數(shù)據(jù),并請求共享或排他鎖時(shí),InnoDB會給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做"間隙(GAP)"。InnoDB也會對這個(gè)"間隙"加鎖,這種鎖機(jī)制就是所謂的間隙鎖(Next-Key鎖)。

Transaction-A
mysql> update innodb_lock set k=66 where id >=6;
Query OK, 1 row affected (0.63 sec)
mysql> commit;
?
Transaction-B
mysql> insert into innodb_lock (id,k,v) values(7,'7','7000');
Query OK, 1 row affected (18.99 sec)

危害(坑):若執(zhí)行的條件是范圍過大,則InnoDB會將整個(gè)范圍內(nèi)所有的索引鍵值全部鎖定,很容易對性能造成影響。

排他鎖

排他鎖,也稱寫鎖,獨(dú)占鎖,當(dāng)前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖。

# Transaction_A
mysql> set autocommit=0;
mysql> select * from innodb_lock where id=4 for update;
+----+------+------+
| id | k    | v    |
+----+------+------+
|  4 | 4    | 4000 |
+----+------+------+
1 row in set (0.00 sec)
?
mysql> update innodb_lock set v='4001' where id=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
?
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
# Transaction_B
mysql> select * from innodb_lock where id=4 for update;
+----+------+------+
| id | k    | v    |
+----+------+------+
|  4 | 4    | 4001 |
+----+------+------+
1 row in set (9.53 sec)

共享鎖

共享鎖,也稱讀鎖,多用于判斷數(shù)據(jù)是否存在,多個(gè)讀操作可以同時(shí)進(jìn)行而不會互相影響。當(dāng)如果事務(wù)對讀鎖進(jìn)行修改操作,很可能會造成死鎖。如下圖所示。

# Transaction_A
mysql> set autocommit=0;
mysql> select * from innodb_lock where id=4 lock in share mode;
+----+------+------+
| id | k    | v    |
+----+------+------+
|  4 | 4    | 4001 |
+----+------+------+
1 row in set (0.00 sec)
?
mysql> update innodb_lock set v='4002' where id=4;
Query OK, 1 row affected (31.29 sec)
Rows matched: 1  Changed: 1  Warnings: 0
# Transaction_B
mysql> set autocommit=0;
mysql> select * from innodb_lock where id=4 lock in share mode;
+----+------+------+
| id | k    | v    |
+----+------+------+
|  4 | 4    | 4001 |
+----+------+------+
1 row in set (0.00 sec)
?
mysql> update innodb_lock set v='4002' where id=4;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

分析行鎖定

通過檢查InnoDB_row_lock 狀態(tài)變量分析系統(tǒng)上的行鎖的爭奪情況 show status like 'innodb_row_lock%'

mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0     |
| Innodb_row_lock_time          | 0     |
| Innodb_row_lock_time_avg      | 0     |
| Innodb_row_lock_time_max      | 0     |
| Innodb_row_lock_waits         | 0     |
+-------------------------------+-------+

innodb_row_lock_current_waits: 當(dāng)前正在等待鎖定的數(shù)量 innodb_row_lock_time: 從系統(tǒng)啟動(dòng)到現(xiàn)在鎖定總時(shí)間長度;非常重要的參數(shù), innodb_row_lock_time_avg: 每次等待所花平均時(shí)間;非常重要的參數(shù), innodb_row_lock_time_max: 從系統(tǒng)啟動(dòng)到現(xiàn)在等待最常的一次所花的時(shí)間; innodb_row_lock_waits: 系統(tǒng)啟動(dòng)后到現(xiàn)在總共等待的次數(shù);非常重要的參數(shù)。直接決定優(yōu)化的方向和策略。

行鎖優(yōu)化

1 盡可能讓所有數(shù)據(jù)檢索都通過索引來完成,避免無索引行或索引失效導(dǎo)致行鎖升級為表鎖。 2 盡可能避免間隙鎖帶來的性能下降,減少或使用合理的檢索范圍。 3 盡可能減少事務(wù)的粒度,比如控制事務(wù)大小,而從減少鎖定資源量和時(shí)間長度,從而減少鎖的競爭等,提供性能。 4 盡可能低級別事務(wù)隔離,隔離級別越高,并發(fā)的處理能力越低。

表鎖

表鎖的優(yōu)勢:開銷??;加鎖快;無死鎖 表鎖的劣勢:鎖粒度大,發(fā)生鎖沖突的概率高,并發(fā)處理能力低 加鎖的方式:自動(dòng)加鎖。查詢操作(SELECT),會自動(dòng)給涉及的所有表加讀鎖,更新操作(UPDATE、DELETE、INSERT),會自動(dòng)給涉及的表加寫鎖。也可以顯示加鎖: 共享讀鎖:lock table tableName read; 獨(dú)占寫鎖:lock table tableName write; 批量解鎖:unlock tables;

共享讀鎖

對MyISAM表的讀操作(加讀鎖),不會阻塞其他進(jìn)程對同一表的讀操作,但會阻塞對同一表的寫操作。只有當(dāng)讀鎖釋放后,才能執(zhí)行其他進(jìn)程的寫操作。在鎖釋放前不能取其他表。

Transaction-A
mysql> lock table myisam_lock read;
Query OK, 0 rows affected (0.00 sec)
?
mysql> select * from myisam_lock;
9 rows in set (0.00 sec)
?
mysql> select * from innodb_lock;
ERROR 1100 (HY000): Table 'innodb_lock' was not locked with LOCK TABLES
?
mysql> update myisam_lock set v='1001' where k='1';
ERROR 1099 (HY000): Table 'myisam_lock' was locked with a READ lock and can't be updated
?
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
Transaction-B
mysql> select * from myisam_lock;
9 rows in set (0.00 sec)
?
mysql> select * from innodb_lock;
8 rows in set (0.01 sec)
?
mysql> update myisam_lock set v='1001' where k='1';
Query OK, 1 row affected (18.67 sec)

獨(dú)占寫鎖

對MyISAM表的寫操作(加寫鎖),會阻塞其他進(jìn)程對同一表的讀和寫操作,只有當(dāng)寫鎖釋放后,才會執(zhí)行其他進(jìn)程的讀寫操作。在鎖釋放前不能寫其他表。

Transaction-A
mysql> set autocommit=0;
Query OK, 0 rows affected (0.05 sec)
?
mysql> lock table myisam_lock write;
Query OK, 0 rows affected (0.03 sec)
?
mysql> update myisam_lock set v='2001' where k='2';
Query OK, 1 row affected (0.00 sec)
?
mysql> select * from myisam_lock;
9 rows in set (0.00 sec)
?
mysql> update innodb_lock set v='1001' where k='1';
ERROR 1100 (HY000): Table 'innodb_lock' was not locked with LOCK TABLES
?
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
Transaction-B
mysql> select * from myisam_lock;
9 rows in set (42.83 sec)

總結(jié):表鎖,讀鎖會阻塞寫,不會阻塞讀。而寫鎖則會把讀寫都阻塞。

查看加鎖情況

show open tables; 1表示加鎖,0表示未加鎖。

mysql> show open tables where in_use > 0;
+----------+-------------+--------+-------------+
| Database | Table       | In_use | Name_locked |
+----------+-------------+--------+-------------+
| lock     | myisam_lock |      1 |           0 |
+----------+-------------+--------+-------------+

分析表鎖定

可以通過檢查table_locks_waited 和 table_locks_immediate 狀態(tài)變量分析系統(tǒng)上的表鎖定:show status like 'table_locks%'

mysql> show status like 'table_locks%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Table_locks_immediate      | 104   |
| Table_locks_waited         | 0     |
+----------------------------+-------+

table_locks_immediate: 表示立即釋放表鎖數(shù)。 table_locks_waited: 表示需要等待的表鎖數(shù)。此值越高則說明存在著越嚴(yán)重的表級鎖爭用情況。

此外,MyISAM的讀寫鎖調(diào)度是寫優(yōu)先,這也是MyISAM不適合做寫為主表的存儲引擎。因?yàn)閷戞i后,其他線程不能做任何操作,大量的更新會使查詢很難得到鎖,從而造成永久阻塞。

什么場景下用表鎖

InnoDB默認(rèn)采用行鎖,在未使用索引字段查詢時(shí)升級為表鎖。MySQL這樣設(shè)計(jì)并不是給你挖坑。它有自己的設(shè)計(jì)目的。 即便你在條件中使用了索引字段,MySQL會根據(jù)自身的執(zhí)行計(jì)劃,考慮是否使用索引(所以explain命令中會有possible_key 和 key)。如果MySQL認(rèn)為全表掃描效率更高,它就不會使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖。因此,在分析鎖沖突時(shí),別忘了檢查SQL的執(zhí)行計(jì)劃,以確認(rèn)是否真正使用了索引。

第一種情況:全表更新。事務(wù)需要更新大部分或全部數(shù)據(jù),且表又比較大。若使用行鎖,會導(dǎo)致事務(wù)執(zhí)行效率低,從而可能造成其他事務(wù)長時(shí)間鎖等待和更多的鎖沖突。

第二種情況:多表級聯(lián)。事務(wù)涉及多個(gè)表,比較復(fù)雜的關(guān)聯(lián)查詢,很可能引起死鎖,造成大量事務(wù)回滾。這種情況若能一次性鎖定事務(wù)涉及的表,從而可以避免死鎖、減少數(shù)據(jù)庫因事務(wù)回滾帶來的開銷。

頁鎖

開銷和加鎖時(shí)間介于表鎖和行鎖之間;會出現(xiàn)死鎖;鎖定粒度介于表鎖和行鎖之間,并發(fā)處理能力一般。只需了解一下。

補(bǔ)充:行級鎖與死鎖

  MyISAM中是不會產(chǎn)生死鎖的,因?yàn)镸yISAM總是一次性獲得所需的全部鎖,要么全部滿足,要么全部等待。而在InnoDB中,鎖是逐步獲得的,就造成了死鎖的可能。

  在MySQL中,行級鎖并不是直接鎖記錄,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種,如果一條sql語句操作了主鍵索引,MySQL就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關(guān)的主鍵索引。 在UPDATE、DELETE操作時(shí),MySQL不僅鎖定WHERE條件掃描過的所有索引記錄,而且會鎖定相鄰的鍵值,即所謂的next-key locking。

  當(dāng)兩個(gè)事務(wù)同時(shí)執(zhí)行,一個(gè)鎖住了主鍵索引,在等待其他相關(guān)索引。另一個(gè)鎖定了非主鍵索引,在等待主鍵索引。這樣就會發(fā)生死鎖。

  發(fā)生死鎖后,InnoDB一般都可以檢測到,并使一個(gè)事務(wù)釋放鎖回退,另一個(gè)獲取鎖完成事務(wù)。

有多種方法可以避免死鎖,這里只介紹常見的三種

  1、如果不同程序會并發(fā)存取多個(gè)表,盡量約定以相同的順序訪問表,可以大大降低死鎖機(jī)會。

  2、在同一個(gè)事務(wù)中,盡可能做到一次鎖定所需要的所有資源,減少死鎖產(chǎn)生概率;

  3、對于非常容易產(chǎn)生死鎖的業(yè)務(wù)部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產(chǎn)生的概率;

總結(jié)

1 InnoDB 支持表鎖和行鎖,使用索引作為檢索條件修改數(shù)據(jù)時(shí)采用行鎖,否則采用表鎖。 2 InnoDB 自動(dòng)給修改操作加鎖,給查詢操作不自動(dòng)加鎖 3 行鎖可能因?yàn)槲词褂盟饕墳楸礞i,所以除了檢查索引是否創(chuàng)建的同時(shí),也需要通過explain執(zhí)行計(jì)劃查詢索引是否被實(shí)際使用。 4 行鎖相對于表鎖來說,優(yōu)勢在于高并發(fā)場景下表現(xiàn)更突出,畢竟鎖的粒度小。 5 當(dāng)表的大部分?jǐn)?shù)據(jù)需要被修改,或者是多表復(fù)雜關(guān)聯(lián)查詢時(shí),建議使用表鎖優(yōu)于行鎖。 6 為了保證數(shù)據(jù)的一致完整性,任何一個(gè)數(shù)據(jù)庫都存在鎖定機(jī)制。鎖定機(jī)制的優(yōu)劣直接影響到一個(gè)數(shù)據(jù)庫的并發(fā)處理能力和性能。

到此這篇關(guān)于MySQL中表鎖和行鎖機(jī)制淺析的文章就介紹到這了,更多相關(guān)MySQL表鎖和行鎖機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql之innodb的鎖分類介紹

    mysql之innodb的鎖分類介紹

    本文將介紹mysql之innodb的鎖分類,需要了解更多的朋友可以參考下
    2012-11-11
  • MySQL中進(jìn)行數(shù)據(jù)的加密和解密存儲的操作方法

    MySQL中進(jìn)行數(shù)據(jù)的加密和解密存儲的操作方法

    在MySQL中,我們可以使用對稱加密算法和非對稱加密算法對數(shù)據(jù)進(jìn)行加密和解密存儲,通過合理選擇加密算法和密鑰管理,可以有效提高數(shù)據(jù)的安全性,防止敏感信息的泄露和非法獲取,下面給大家分享MySQL中進(jìn)行數(shù)據(jù)的加密和解密存儲方法,感興趣的朋友一起看看吧
    2024-05-05
  • MySQL5.7完全卸載步驟詳解

    MySQL5.7完全卸載步驟詳解

    這篇文章主要介紹了MySQL5.7完全卸載的詳細(xì)步驟以及把中間遇到的問題做了分析,需要的朋友跟著操作下吧。
    2018-02-02
  • MySQL預(yù)編譯功能詳解

    MySQL預(yù)編譯功能詳解

    這篇文章主要為大家詳細(xì)介紹了MySQL預(yù)編譯功能的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Mysql合并結(jié)果接橫向拼接字段的實(shí)現(xiàn)步驟

    Mysql合并結(jié)果接橫向拼接字段的實(shí)現(xiàn)步驟

    這篇文章主要給大家介紹了關(guān)于Mysql合并結(jié)果接橫向拼接字段的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • MySQL count(1)、count(*)、count(字段)的區(qū)別

    MySQL count(1)、count(*)、count(字段)的區(qū)別

    COUNT在數(shù)據(jù)庫行數(shù)統(tǒng)計(jì)中被廣泛使用,那么你知道MySQL count(1)、count(*)、count(字段)的區(qū)別嗎,本文就想的介紹一下,感興趣的可以了解一下
    2021-12-12
  • mysql/Java服務(wù)端對emoji的支持與問題解決方法詳解

    mysql/Java服務(wù)端對emoji的支持與問題解決方法詳解

    這篇文章主要介紹了mysql/Java服務(wù)端對emoji的支持與問題解決方法,結(jié)合實(shí)例形式分析了mysql/Java服務(wù)端對emoji字符集存儲及支持問題解決方法,需要的朋友可以參考下
    2019-10-10
  • 詳解在MySQL中創(chuàng)建表的教程

    詳解在MySQL中創(chuàng)建表的教程

    這篇文章主要介紹了詳解在MySQL中創(chuàng)建表的教程,是MySQL入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-05-05
  • MySql版本問題sql_mode=only_full_group_by的完美解決方案

    MySql版本問題sql_mode=only_full_group_by的完美解決方案

    這篇文章主要介紹了MySql版本問題sql_mode=only_full_group_by的完美解決方案,需要的朋友可以參考下
    2017-07-07
  • MySQL多表查詢詳解下

    MySQL多表查詢詳解下

    這篇文章主要介紹了MySQL多表查詢詳解下,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評論