MySQL:事务会锁定行吗?


13

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

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

user1:更新表集column = column-4,其中column_id = 1;

user2:更新表集column = column-7,其中column_id = 1;

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

如果第三位用户发出选择声明怎么办?MySQL将返回什么值?

PS这将在Innodb上。

Answers:


17

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

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

InnoDB仅锁定行,而不锁定表。(好的,DDL语句执行粗体锁。)

变得更有趣的是修改两件事或花费大量时间的事务:

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

BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;

选择需要这样写:

SELECT something  FOR UPDATE;

这告诉其他连接“我打算更新该行;请不要弄乱我”。(我举了这个例子,因为很多新手都错过了这个技巧。)

死锁情况:遇到 两件事:

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;

这是死锁的经典示例-每个人都抓住一件事,然后伸手去拿另一件事。显然,它无法正常工作。一笔交易被杀死;另一个完成。因此,您必须检查是否有错误,以便能够发现它。

对死锁的正常反应是重播整个失败的事务。届时,其他连接将不会受到干扰,并且应该继续进行而不会遇到麻烦。(好的,另一个连接可能会导致另一个死锁。)

延迟情况:如果两个连接以相同顺序抓取多个对象,则可以延迟一个直到另一个完成。为了避免这种情况“永远等待”,默认为50秒innodb_lock_wait_timeout。您的简单对UPDATEs实际上就是这种情况的一个例子。一个会迅速完成;另一个则停滞不前,直到第一个完成为止。

请注意,通过始终如一地排列触摸物体的方式,可以将“死锁”(在某些情况下)转变为“延迟”。

autocommit = 1: 使用此设置并且不调用BEGIN,每个语句实际上是:

BEGIN;
your statement
COMMIT;

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.