select for update加了行锁还是表锁?

在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中,因为查询条件没有命中索引,所以加的是表级锁。