我之前没有尝试过使用 MySQL 事务,我只是想澄清一些事情。
如果两个用户在非常精确的时间执行查询,MySQL 将如何处理呢?例如,用户正在尝试更新记录。
user1:更新表集column = column - 4 where column_id = 1;
user2: 更新表集 column = column - 7 where column_id = 1;
现在如果我使用事务,MySQL会选择首先执行哪个查询并锁定第二个用户,直到第一个查询被提交?那是表锁还是行锁?
如果第三个用户将发出选择语句怎么办?MySQL 将返回的值是多少?
PS这将在Innodb上。
像这样的单个语句与 MyISAM 或 InnoDB、事务或 autocommit=ON 相同。它阻塞了足够的查询,从而阻塞了另一个连接。完成后,另一个连接继续进行。在所有情况下,该列很快都会减少 11。
第三个用户可能会看到该值减少了 0 或 4 或 7 或 11。“非常精确的时间”实际上是不可能的,因为在每个语句的执行中的某个时刻,检查/设置/任何一个单线程锁. 也就是说,它们会被序列化,速度快到你看不到。
InnoDB 只锁定行,而不锁定表。(好的,DDL 语句做更粗的锁。)
更有趣的是修改两件事的事务,或者需要相当长的时间:
意向案例:单项但需要时间:
选择需要这样写:
这告诉其他连接“我打算更新该行;请不要搞砸我”。(我举了这个例子,因为很多新手都错过了这个微妙之处。)
死锁案例: 搞砸两件事:
这是僵局的典型例子——每个人都抓住一件东西,然后伸手去拿另一件东西。显然它不能工作。一笔交易被杀死;另一个完成。因此,您必须检查错误,以便发现它。
对死锁的正常反应是重播整个失败的事务。届时,其他连接将不会受到干扰,并且应该可以顺利进行。(好的,另一个连接可能会造成另一个死锁。)
延迟案例:如果两个连接以相同的顺序抓取多个东西,那么一个可以延迟到另一个完成。为了避免“永远等待”,有一个默认的 50-second
innodb_lock_wait_timeout
。你这双简单UPDATEs
的其实就是这种情况的一个例子。一个会及时完成;另一个停滞不前,直到第一个完成。请注意死锁如何(在某些情况下)通过始终如一地对您触摸的事物进行排序而变成延迟。
autocommit=1: 使用此设置且无需调用
BEGIN
,每条语句都有效:autocommit=0: 这是等待发生的麻烦。执行写入查询时,
BEGIN
会隐式生成 a。但是,您有责任最终发出COMMIT
. 如果您不这样做,您会想知道为什么您的系统会挂起。(另一个常见的新手错误。)我的建议:“永远不要使用=0
”。