简体   繁体   English

SELECT为什么要等待锁?

[英]Why does a SELECT wait for a lock?

In my application I have the problem that sometimes SELECT statements run into a java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction 在我的应用程序中,我遇到一个问题,有时SELECT语句会运行到java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction exception. java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction异常。 Sadly I can't create an example as the circumstances are very complex. 遗憾的是,由于情况非常复杂,我无法创建示例。 So the question is just about general understanding. 因此,问题只是关于一般的了解。

A little bit of background information: I'm using MySQL (InnoDB) with READ_COMMITED isolation level. 一些背景信息:我正在使用具有READ_COMMITED隔离级别的MySQL(InnoDB)。

Actually I don't understand how a SELECT can ever run into a lock timeout with that setup. 实际上,我不了解SELECT如何通过该设置遇到锁定超时。 I thought that a SELECT would never lock as it will just return the latest commited state (managed by MySQL). 我以为SELECT永远不会锁定,因为它只会返回最新的提交状态(由MySQL管理)。 Anyway according to what is happening this seems to be wrong. 无论如何,根据发生的事情,这似乎是错误的。 So how is it really? 那真的怎么样?

I already read this https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html but that didn't really give me a clue. 我已经读过这个https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html,但这并没有真正给我一个线索。 No SELECT ... FOR UPDATE or something like that is used. 没有SELECT ... FOR UPDATE或类似的东西被使用。

That is probably due to your database. 那可能是由于您的数据库。 Usually this kind of problems come from that side, not from the programming side that access it.In my experience with db's, these problems are usually due to that. 通常,这类问题来自那一侧,而不是来自访问它的编程一侧。以我对db的经验来看,这些问题通常是由于这一点造成的。 In the end, the programming side is just "go and get that for me in that db" thing. 最后,编程方面只是“在数据库中为我自己准备”。

I found this without much effort. 我发现很费力。

It basically explains that: 它的基本解释是:

Lock wait timeout occurs typically when a transaction is waiting on row(s) of data to update which is already been locked by some other transaction. Lock wait timeout通常发生在事务正在等待要更新的数据行(该数据已被某个其他事务锁定)时。

You should also check this answer that has a specific transaction problem, which might help you, as trying to change different tables might do the timeout 您还应该检查有特定事务问题的答案 ,这可能会对您有所帮助,因为尝试更改其他表可能会导致超时

the query was attempting to change at least one row in one or more InnoDB tables. 查询试图更改一个或多个InnoDB表中的至少一行。 Since you know the query, all the tables being accessed are candidates for being the culprit. 由于您知道查询,因此所有被访问的表都是罪魁祸首。

To speed up queries in a DB, several transactions can be executed at the same time. 为了加快数据库中的查询,可以同时执行多个事务。 For example if someone runs a select query over a table for the wages of the employees of a company (each employee identified by an id) and another one changes the last name of someone who eg has married, you can execute both queries at the same time because they don't interfere. 例如,如果某人在一个表上对公司雇员(每个雇员由一个ID标识)的工资进行选择查询,而另一个人更改了已婚某人的姓氏,则您可以在同一时间执行这两个查询时间,因为他们不干涉。

But in other cases even a SELECT statement might interfere with another statement. 但是在其他情况下,即使是SELECT语句也可能会干扰另一个语句。

To prevent unexpected results in a SQL transactions, transactions follow the ACID-model which stands for Atomicity, Consistency, Isolation and Durability (for further information read wikipedia ). 为了防止SQL事务中出现意外结果,事务遵循ACID模型 ,该模型代表原子性,一致性,隔离性和持久性(有关更多信息,请参阅Wikipedia )。

Let's say transaction 1 starts to calculate something and then wants to write the results to table A. Before writing it it locks all SELECT statements to table A. Otherwise this would interfere with the Isolation requirement. 假设事务1开始计算某些东西,然后想要将结果写入表A。在写入之前,它将所有SELECT语句锁定到表A。否则,这会干扰隔离要求。 Because if a transaction 2 would start while 1 is still writing, 2's results depend on where 1 has already written to and where not. 因为如果事务2将在1仍在写入时开始,则2的结果取决于1已写入的位置和未写入的位置。

Now, it might even produce a dead-lock . 现在,它甚至可能产生死锁 Eg before transaction 1 can write the last field in table A, it still has to write something to table B but transaction 2 has already blocked table B to read safely from it after it read from A and now you have a deadlock. 例如,在事务1可以写入表A中的最后一个字段之前,它仍然必须向表B中写入内容,但是事务2已经阻止了表B,以便在从表A中读取后安全地从表B中读取数据,现在您已陷入僵局。 2 wants to read from A which is blocked by 1, so it waits for 1 to finish but 1 waits for 2 to unlock table B to finish by itself. 2想要从被1阻塞的A中读取数据,因此它等待1完成,但是1等待2解锁表B完成。

To solve this problem one strategy is to rollback certain transactions after a certain timeout. 为了解决此问题,一种策略是在特定超时后回滚特定事务。 ( more here ) 更多在这里

So that might be a read on for your select statement to get a lock wait timeout exceeded. 因此,这可能是您的select语句的继续阅读,以获得超出锁定等待超时的时间。

But a dead-lock usually just happens by coincidence, so if transaction 2 was forced to rollback, transaction 1 should be able to finish so that 2 should be able to succeed on a later try. 但是僵局通常只是偶然发生,因此,如果事务2被迫回滚,事务1应该能够完成,以便事务2在以后的尝试中能够成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM