我修改下答案,之前說的update的讀會先加S鎖再升級成X鎖這個說法是不正確的,這個回答是我之前在一位大V的部落格中看到的,而沒有自己去求證驗證誤導大家,不好意思,我特意看了下mysql的官方文件,並且經過驗證,MySQL的update語句在讀的時候就直接加的X鎖,會阻塞其它的DML語句的讀(insert, update, delete等),所以不會發生死鎖,我的驗證思路是:
create table tt(a int, b int, primary key(a)) engine=innodb;
insert into tt values(1, 1);
然後開啟一個顯示事務t1
begin;
update tt set b=1 where a=1;
先不提交
再開一個session2,也開啟一個事務t2:
雖然t1並沒有發生實際的更新,但是t2的事務會一直等在行鎖上,被阻塞住,commit t1後t2可以繼續執行,由此可見,update的讀是加的X鎖,所以不會發生死鎖
這個地方感覺SQL Server做得更好,SQL Server的update語句在讀的時候會加U鎖,U鎖是一種介於S鎖和X鎖之間的鎖,而且只有U鎖可以升級成X鎖,當一行上有S鎖,可以加U鎖,當一行上有U鎖,不能再繼續加X鎖或者U鎖,但是可以加S鎖,當持有U鎖的行需要被更新的時候會升級成X鎖,這樣就保證了只有一個人能持有可變更的鎖,避免了死鎖,而同時又沒有因為直接上X鎖而阻塞太廣。
我修改下答案,之前說的update的讀會先加S鎖再升級成X鎖這個說法是不正確的,這個回答是我之前在一位大V的部落格中看到的,而沒有自己去求證驗證誤導大家,不好意思,我特意看了下mysql的官方文件,並且經過驗證,MySQL的update語句在讀的時候就直接加的X鎖,會阻塞其它的DML語句的讀(insert, update, delete等),所以不會發生死鎖,我的驗證思路是:
create table tt(a int, b int, primary key(a)) engine=innodb;
insert into tt values(1, 1);
然後開啟一個顯示事務t1
begin;
update tt set b=1 where a=1;
先不提交
再開一個session2,也開啟一個事務t2:
begin;
update tt set b=1 where a=1;
雖然t1並沒有發生實際的更新,但是t2的事務會一直等在行鎖上,被阻塞住,commit t1後t2可以繼續執行,由此可見,update的讀是加的X鎖,所以不會發生死鎖
這個地方感覺SQL Server做得更好,SQL Server的update語句在讀的時候會加U鎖,U鎖是一種介於S鎖和X鎖之間的鎖,而且只有U鎖可以升級成X鎖,當一行上有S鎖,可以加U鎖,當一行上有U鎖,不能再繼續加X鎖或者U鎖,但是可以加S鎖,當持有U鎖的行需要被更新的時候會升級成X鎖,這樣就保證了只有一個人能持有可變更的鎖,避免了死鎖,而同時又沒有因為直接上X鎖而阻塞太廣。