MySQL:事务会锁定行吗?

zer*_*r09 16 mysql innodb transaction locking

我之前没有尝试过使用 MySQL 事务,我只是想澄清一些事情。

如果两个用户在非常准确的时间执行查询,MySQL 将如何处理?例如,用户正在尝试更新记录。

user1:更新表集 column = column - 4 where column_id = 1;

user2:更新表集 column = column - 7 where column_id = 1;

现在,如果我使用事务,MySQL 是否会选择首先执行哪个查询并锁定第二个用户,直到提交第一个查询?那是表锁还是行锁?

如果第三个用户将发出 select 语句怎么办?MySQL 将返回的值是什么?

PS 这将在 Innodb 上。

Ric*_*mes 21

像这样的单个语句对于 MyISAM 或 InnoDB、事务或 autocommit=ON 的工作方式相同。它阻塞足以执行查询,从而阻塞其他连接。完成后,另一个连接继续。在所有情况下,该列很快就会减少 11。

第三个用户可能会看到值减少了 0 或 4 或 7 或 11。“非常精确的时间”实际上是不可能的,因为在执行每个语句的某个时刻,会检查/设置/设置单线程锁. 也就是说,它们被序列化,速度快到你看不到。

InnoDB 只锁定行,而不锁定表。(好吧,DDL 语句做更粗的锁。)

更有趣的是一个交易修改了两件事,或者花费了大量时间:

意向案例:单个项目但需要时间:

BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

选择需要这样写:

SELECT something  FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)

这告诉其他连接“我打算更新该行;请不要把我搞砸”。(我举了这个例子,因为很多新手都忽略了这个微妙之处。)

死锁案例: 搞砸了两件事:

BEGIN;    -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;

BEGIN;    -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

这是僵局的典型例子——每个人抓住一件东西,然后伸手去拿另一件东西。显然它不能工作。一笔交易被杀死;另一个完成。因此,您必须检查错误,以便您可以发现它。

对死锁的正常反应是重放整个失败的事务。到那时,另一个连接将不会受到干扰,它应该可以顺利进行。(好吧,另一个连接可能会造成另一个死锁。)

延迟案例:如果两个连接以相同的顺序抓取多个东西,那么一个可以延迟到另一个完成。为了避免“永远等待”,有一个默认的 50-second innodb_lock_wait_timeout。你的一对简单UPDATEs实际上就是这种情况的一个例子。一个会很快完成;另一个停止直到第一个完成。

注意死锁是如何(在某些情况下)通过对你接触的东西进行一致排序而变成延迟的。

自动提交= 1: 通过此设置不调用BEGIN,每个语句实际上是:

BEGIN;
your statement
COMMIT;
Run Code Online (Sandbox Code Playgroud)

autocommit=0: 这是等待发生的麻烦。执行写入查询时,BEGIN会隐式生成 a。但是,您有责任最终发布COMMIT. 如果你不这样做,你会想知道为什么你的系统挂了。(另一个常见的新手错误。)我的建议:“永远不要使用=0”。

  • 该设置仅适用于您还调用“LOCK TABLES”的某些情况,您不应考虑在 InnoDB 中使用它。 (2认同)