在MySQL中,使用SELECT ... FOR UPDATE语句可以对查询结果进行加锁,以保证在事务中其它会话不能修改这些记录。默认情况下,使用SELECT ... FOR UPDATE语句会对查询结果加行级锁,但如果查询条件中包含索引字段,则会对该索引加锁,这时就是索引级锁。
因此,具体SELECT ... FOR UPDATE语句加的是行锁还是表锁,取决于查询条件和索引情况。如果查询条件中没有索引,也没有全表扫描,则会对查询结果加表级锁。.
假设有以下表结构:
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
现在有两个事务T1和T2,要对用户表进行查询和更新操作:
事务T1:
BEGIN;
SELECT * FROM user WHERE name = '张三' FOR UPDATE;
-- 对查询结果加行锁或索引锁,取决于idx_name是否被命中
UPDATE user SET age = 30 WHERE name = '张三';
COMMIT;
事务T2:
BEGIN;
SELECT * FROM user WHERE age > 20 FOR UPDATE;
-- 对查询结果加表级锁,因为没有命中索引
UPDATE user SET age = 25 WHERE age > 20;
COMMIT;
在T1中,如果idx_name索引被命中,那么加的是索引锁,否则加的是行锁。在T2中,因为查询条件没有命中索引,所以加的是表级锁。