有比事务更高效的方法吗?

3
insert into table1 ...;
update table2 set count=count+1;

以上代码向table1插入了一些内容,如果成功,则更新table2中的count字段。
当然,这种情况可以通过事务来处理,但是事务需要锁定表,在高并发系统中效率不高。如果您需要在该事务中更新多个表格,情况可能会更糟。
你有什么解决方案吗?
我正在使用PHP,并以以下方式实现事务:
mysql_query('begin');

mysql_query($statement1);

mysql_query($statement2);
...
mysql_query('commit');

所以看起来所有在这些$statement中引用的表都会被锁定?
6个回答

3

MySQL中,事务(假定为InnoDB)不需要锁定整个表。

INSERT将锁定单个行而不使用间隙锁。

如果在WHERE子句中提供了一个索引字段的等式或IN条件,则UPDATE也不会锁定任何间隙。

这意味着,对于一个正确建立索引的表来说,INSERTs不会相互阻塞,而UPDATEs只有在它们影响相同行时才会相互阻塞。

当然,UPDATE会锁定它所影响的单个行,但由于它是您事务中的最后一个操作,因此在操作提交后立即解除锁定。

实际上,锁定本身是必需的,这样两个并发更新就会按顺序递增计数。


INSERTs 可能不会在行级锁上互相阻塞,但它们仍然可能与表中索引上的锁发生冲突,而且确实还可能彼此死锁。我见过这种情况。 - MarkR
@MarkR:你说得对,这也就是我特别提到“正确索引的表”的原因。这里有一个关于你所讲问题的问题:https://dev59.com/EEvSa4cB1Zd3GeqPbArA - Quassnoi

2

使用InnoDB存储引擎。它采用行级锁定,而不是MyISAM的表级锁定。


或者你可以切换到Oracle,它(在大多数情况下)不执行锁定。 :) - LBushkin
@LBushkin:在Oracle中,对永久表进行任何DML操作都会锁定受影响的行,直到事务结束。 - Quassnoi
Oracle会锁定相关的行 - 这是获取正确的事务行为所必需的。 - MarkR

2

1

这更像是一个“触发器”的工作。在插入时做一些事情。


MySQL的哪个版本实现了稳定的触发器? - user198729

1

事务非常适合确保“全有或全无”的行为——即使您的系统负载或并发性很高,您也不应该停止使用事务,至少如果您需要数据保持一致!

(而事务不一定会锁定整个表)


0
如果速度是绝对重要的因素,我可能会倾向于在内存中缓存更新计数(使用线程安全代码),并定期将其写回数据库。当我这样做时,我一定会使用事务。这样做的缺点是你需要愿意将计数视为近似值。如果你需要它在一个操作中绝对正确,那么它需要在事务内重新计算。
正如其他人所指出的,使用支持行级锁定的数据库,并简单地使用显式(或隐式通过触发器)事务可能更容易。这肯定更准确和更安全。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接