MySQL:事务会锁定行吗?

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

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

user1:update table set column = column – 4其中column_id = 1;

user2:update table set column = column – 7其中column_id = 1;

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

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

附:这将是Innodb.

解决方法:

像这样的单个语句与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.你的一对简单UPDATE实际上是这种情况的一个例子.一个人会很快完成;另一个停滞直到第一个结束.

请注意,通过不断地对您触摸的内容进行排序,可以将死锁(在某些情况下)转换为延迟.

autocommit = 1:使用此设置并且不调用BEGIN,每个语句都是有效的:

BEGIN;
your statement
COMMIT;

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

上一篇:mysql – InnoDB和隔离级别 – 不可重复读取不好的东西?


下一篇:mysql – 如何以线程安全的方式查询和增加值(计数器)? (避免竞争条件)