Answers:
像这样的单个语句对于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
”。