MySQL 兩表join時加鎖情況


MariaDB [test]> desc leouser_inno;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int(11)      | NO   | PRI | NULL    |       |
| name  | varchar(100) | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
MariaDB [test]> select * from leouser_inno;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | changefrom2 |
|  5 | leo2        |
|  7 | leo7        |
+----+-------------+




MariaDB [test]> desc leouser2_inno;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| name  | varchar(30) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

MariaDB [test]> select * from leouser2_inno;
+----+------+
| id | name |
+----+------+
|  1 | leo  |
|  4 | leo4 |
+----+------+

 

事務隔離級別為Repeatable Read

test1: begin;
select * from leouser_inno straight_join leouser2_inno on leouser_inno.id = leouser2_inno.id for update;
--鎖住兩個表的所有record和gap

test2: begin; -- 加入主鍵過濾
select * from leouser_inno straight_join leouser2_inno on leouser_inno.id = leouser2_inno.id where leouser2_inno.id=1 for update;
--各自lock id=1的record, 沒有lock gap

test2.1:begin; -- change join table order
-- exactly the same result with test2


test3:begin; -- 主鍵范圍過濾
MariaDB [test]> select * from leouser_inno straight_join leouser2_inno on leouser_inno.id = leouser2_inno.id where leouser2_inno.id<3 for update;
-- leouser2_inno的id=1的記錄lock,id=4右邊gaplock,id=2,3的gap沒有lock,但是沒有選中的記錄不會lock。由於先select leouser_inno的所有記錄,對leouser2_inno 的select很名確(where id=1 or id=5),id=5在leouser2_inno 的最大id=4的右邊,如果不對id=4的右側gap加鎖,可能導致幻讀,而對id=2,3的insert在leouser_inno
-- leouser_inno的所有record都lock,所有gap都lock。
insert into leouser2_inno(id) values(0);的時候有個小插曲,不能插入,以為id=1的左側也是gap lock,想不通。其實是因為leouser2_inno.id是autoincrement的,當id=0或者null的時候自動增加到mysql維護的下一個id,也就是id=5,而id=5是gaplock狀態導致不能insert。
SET sql_mode='NO_AUTO_VALUE_ON_ZERO';
當前session設置后,可以insert id=0的record,因此,不矛盾。

test3.1 -- reorder join tables;

MariaDB [test]> begin;
Query OK, 0 rows affected (0.000 sec)

MariaDB [test]> select * from leouser2_inno straight_join leouser_inno on leouser_inno.id = leouser2_inno.id where leouser2_inno.id<3 for update;
+----+------+----+-------------+
| id | name | id | name        |
+----+------+----+-------------+
|  1 | leo  |  1 | changefrom2 |
+----+------+----+-------------+
1 row in set (0.004 sec)

 

leouser2_inno 發現所有record被加鎖;相關gap被lock。why all records locked but not all gaps locked??——是因為RR事務隔離級別下,唯一索引上查詢時使用的lock類型next-key lock,除非等號過濾條件(可以是or連接的多個相等條件),並且對應的等號條件查詢到了一條記錄,MySQL做了優化此時退化為record lock,本測試中不適用於優化情形,仍是next-key lock。leouser2_inno中的鎖有3個:(-infinite,1],(1,4],(4,+infinite)。

leouser_inno 只有符合條件的id=1一條record被lock,只有record lock,因此其他的record沒有被加鎖。
=============
總結,join的時候mysql straight_join阻止優化select表的順序,按照從左到右結合where條件查詢,對第一個表加相應的鎖,得到記錄后作為條件查詢第二個表,對第二個表加鎖。多表join時屬於嵌套情況。join情況的加鎖就是多個表依次查詢——加鎖,和分析單表查詢相同,其結果通過mysql server層連接返回客戶端。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM