繼續之前的話題:
在連線1中執行commit操作:
查詢當前表資料:
select * from test_alr;
id name
1 張三
2 李四
3 王五
4 趙六
5 孫七
在連線1開啟事務,然後對id=1的行加行鎖:
set autocommit=0;
select * from test_alr where id=1 for update;
此時在連線2對id=1的行進行update操作:
update test_alr set name='test' where id=1;
在等待了一段時間之後報等待超時錯誤:
error code : 1205
lock wait timeout exceeded; try restarting transaction
然後對id=2的行進行update操作
update test_alr set name='test' where id=2;
1 row(s) affected
發現成功執行,此時的test_alr進行的是行級鎖而不是表級鎖
因為行鎖是需要根據索引列來做判斷的,所以如果用子查詢讀取出來的資料當做索引列鎖定的行數的時候會發現鎖的是表而不是行,除非子查詢中的表和外表之前有主外來鍵關係,建立test_alr的外來鍵表:
drop table if exists test_rla;
create table test_rla
( id int not null auto_increment comment 'id',
primary key (id),
constraint test_line_lock foreign key (id) references test_alr (id)
) engine=innodb auto_increment=1 default charset=utf8 ;
往表中插入測試資料:
insert into test_rla values (1),(2),(3),(4),(5);
然後用子查詢對錶test_alr加行鎖:
select * from test_alr where id in (select id from test_rla) for update;
然後在連線2中對id=2,3的行進行update操作
update test_alr set name='test' where id=2;
error code : 1205
lock wait timeout exceeded; try restarting transaction
update test_alr set name='test' where id=3;
error code : 1205
lock wait timeout exceeded; try restarting transaction
實際測試時1-5都出現鎖表情況了,當update id=7的時候:
update test_alr set name='test' where id=7;
1 row(s) affected
證明update成功了,所以證明有主外來鍵關係的子查詢是可以加行鎖的,猜測原理大概是因為mysql對錶加行鎖的時候,實際上是在索引列上的每一行都打了個標記,而其他連線判斷該錶的某行是否發生行鎖的話直接讀取索引的資訊就能夠解決問題了,而主外來鍵關係的子查詢關聯條件其實是走的索引,而不是通過掃瞄子查詢中的實際資料,所以可以加行鎖,所以如果沒有主外來鍵關係的子查詢,因為mysql並不知道子查詢表中的資料到底是什麼樣的,所以不能對其加行鎖,而是對外表加的表級鎖 mysql的行鎖與表鎖
mysql 行鎖與表鎖 只根據主鍵進行查詢,並且查詢到資料,主鍵字段產生行鎖。begin select from table where id 1 for update commit 只根據主鍵進行查詢,沒有查詢到資料,不產生鎖。begin select from table where id 1 ...
Mysql行鎖與表鎖
用主鍵修改就是行瑣,或者用索引修改就是行瑣 update tab set name xx where id xx 行鎖 update tab set name xx where date 非主鍵或索引 xx 表鎖 插入的時候呢?插入都是行鎖 alert語句修改表結構,表鎖 表鎖和行鎖同時發生時,會等...
mysql 行鎖與表鎖
為日常整理,可能會有些重複.行鎖表表鎖 1 多個事務操作同一行資料時,後來的事務處於阻塞等待狀態。這樣可以避免了髒讀等資料一致性的問題。後來的事務可以操作其他行資料,解決了表鎖高併發效能低的問題。2 innodb的行鎖是針對索引加的鎖,不是針對記錄加的鎖。並且該索引不能失效,否則都會從行鎖公升級為表...