SELECT ... FOR UPDATE和MAX()

时间:2011-07-06 08:12:42

标签: mysql select innodb

此查询中的SELECT ... FOR UPDATE是否锁定此表中的行?

表在InnoDB中,查询在内部交易

select max(id) from table1 FOR UPDATE

我有这段代码,似乎SELECT ... FOR UPDATE没有锁定行。

5 个答案:

答案 0 :(得分:2)

SELECT ... FOR UPDATE阻止其他会话执行SELECT ... LOCK IN SHARE MODE

改为使用SELECT ... LOCK IN SHARE MODE

  

在行上设置共享模式锁定   读。共享模式锁启用其他   会话来读取行而不是   修改它们。读取的行是   最新的,如果他们属于   还没有的另一笔交易   已提交,读取块直到那个   交易结束。

请参阅docs

答案 1 :(得分:1)

或许这可行吗? :

select id from table where id IN (select max(id) from table1) FOR UPDATE

答案 2 :(得分:1)

我也偶然发现了这个问题并进行了测试。

CREATE TABLE `test1` (
  `user_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `ds_id` mediumint(8) unsigned NOT NULL,
  `producer_id` mediumint(8) unsigned NOT NULL DEFAULT 0,
  PRIMARY KEY (`user_id`,`ds_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `test1` VALUES
(3, 4, 2),
(17, 1, 1),
(18, 1, 9);

线程1:

begin;
select max(ds_id) from test1 where user_id=3 for update;
+------------+
| max(ds_id) |
+------------+
|          3 |
+------------+

线程2:

begin;
select max(ds_id) from test1 where user_id=3 for update;
... waiting ...

线程1:

insert into test1 set user_id=3, ds_id=4, producer_id=1;
commit;

线程2:

+------------+
| max(ds_id) |
+------------+
|          3 |
+------------+

使用组功能时,InnoDB不会锁定间隙,而只是锁定现有记录。如果没有组功能,线程2将按预期返回2行,包括全新的行。

答案 3 :(得分:0)

SELECT MAX(id) FROM table1 FOR UPDATE - 不会锁定任何行,因为它实际上并不扫描任何行。从表索引中检索所需信息。

如果您在查询前加DESCRIBE,则显示:

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
'1', 'SIMPLE', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Select tables optimized away'

SELECT id FROM table1 WHERE id = (SELECT MAX(id) FROM table1) FOR UPDATE - 将锁定与MAX(id)匹配的一行,因为您明确检索了该行。

SELECT id FROM table1 ORDER BY id DESC LIMIT 1 FOR UPDATE - 将使用MAX(id)ORDER BY的组合锁定所有行并检索LIMIT 1

这将再次由DESCRIBE查询解释。

答案 4 :(得分:-2)

与Oracle文档中一样 本条款受以下限制: 您不能使用以下其他构造指定此子句:DISTINCT运算符,CURSOR表达式,集合运算符,group_by_clause或聚合函数。