1. 程式人生 > >MySQL 兩表join時加鎖情況

MySQL 兩表join時加鎖情況

tab 記錄 val 其他 into 得到 date maria 順序

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,除非where clause指定使用等號過濾只會查詢到一條記錄,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層連接返回客戶端。

MySQL 兩表join時加鎖情況