Answers:
您正在使用交易;autocommit不会禁用事务,它只是使它们在语句末尾自动提交。
发生的情况是,某个其他线程在某个记录上保持记录锁定(您正在更新表中的每个记录!)的时间太长,导致您的线程超时。
您可以通过以下方式查看事件的更多详细信息:
SHOW ENGINE INNODB STATUS
事件之后(在sql
编辑器中)。理想情况下,请在安静的测试机上执行此操作。
process
空闲。如果是这样,您可能会收到此错误。我对吗?
connection.commit()
提交。INSERT
UPDATE
如何为MySQL中的锁定表强制解锁:
像这样破坏锁可能会导致在导致锁的sql语句上不强制执行数据库中的原子性。
这是骇人听闻的,正确的解决方案是修复导致锁定的应用程序。但是,当美元紧缩时,迅速的踢动将使事情再次发生变化。
1)输入MySQL
mysql -u your_user -p
2)让我们看看锁定表的列表
mysql> show open tables where in_use>0;
3)让我们看一下当前进程的列表,其中之一正在锁定您的表
mysql> show processlist;
4)杀死其中一个进程
mysql> kill <put_process_id_here>;
mysql> set innodb_lock_wait_timeout=100
Query OK, 0 rows affected (0.02 sec)
mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100 |
+--------------------------+-------+
现在再次触发锁定。您有100秒的时间向SHOW ENGINE INNODB STATUS\G
数据库发出A ,并查看有哪些其他事务正在锁定您的事务。
lock_wait_timeout
价值
看一下您的数据库是否经过微调。尤其是事务隔离。增加innodb_lock_wait_timeout变量不是一个好主意。
在mysql cli中检查数据库事务隔离级别:
mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ | REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)
您可以通过更改隔离级别来获得改进,使用像READ COMMITTED这样的oracle来代替REPEATABLE READ(InnoDB默认值)
mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql>
也请仅在必要时尝试使用SELECT FOR UPDATE。
tx_isolation
变量重命名为transaction_isolation
。
行数不是很多...如果不是主键,请在account_import_id上创建索引。
CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
如果您刚刚杀死了一个大查询,将需要一些时间到rollback
。如果在终止的查询完成回滚之前发出另一个查询,则可能会收到锁定超时错误。那就是我发生的事情。解决的办法是稍等一下。
细节:
我已经发出了DELETE查询,以删除大约100万行中的大约900,000。
我错误地运行了此命令(仅删除了10%的行):
DELETE FROM table WHERE MOD(id,10) = 0
代替此操作(删除90%的行):
DELETE FROM table WHERE MOD(id,10) != 0
我想删除90%的行,而不是10%。因此,我在MySQL命令行中终止了该进程,因为它知道该进程将回滚到目前为止已删除的所有行。
然后,我立即运行了正确的命令,并在lock timeout exceeded
之后不久出现了错误。我意识到,锁实际上可能是rollback
仍在后台发生的被杀死查询的锁。因此,我等待了几秒钟,然后重新运行查询。
确保数据库表正在使用InnoDB存储引擎和READ-COMMITTED事务隔离级别。
您可以通过SELECT @@ GLOBAL.tx_isolation,@@ tx_isolation进行检查;在mysql控制台上。
如果未将其设置为READ-COMMITTED,则必须进行设置。在设置它之前,请确保您在mysql中具有SUPER特权。
您可以从http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html寻求帮助。
通过设置此选项,我认为您的问题将得到解决。
您可能还想检查一下您是否不想同时在两个进程中进行更新。在这种情况下,用户(@tala)遇到了类似的错误消息,也许要仔细检查一下...
我来自Google,我只是想添加对我有用的解决方案。我的问题是我正在尝试删除级联很多FK的大表的记录,因此我得到了与OP相同的错误。
我禁用了该功能autocommit
,然后仅COMMIT
在SQL语句的末尾添加了它。据我了解,这会一点一点地释放缓冲区,而不是在命令末尾等待。
为了与OP的示例保持一致,这应该可行:
mysql> set autocommit=0;
mysql> update customer set account_import_id = 1; commit;
autocommit
如果您想像以前一样保留MySQL配置,请不要忘记再次激活。
mysql> set autocommit=1;
在我的实例中,我正在运行异常查询以修复数据。 如果您锁定查询中的表,则无需处理锁定超时:
LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;
对于正常使用,这可能不是一个好主意。
有关更多信息,请参见: MySQL 8.0参考手册
我遇到了具有2个Doctrine DBAL连接的情况,其中之一是非事务性的(用于重要日志),它们旨在并行运行,而不依赖于彼此。
CodeExecution(
TransactionConnectionQuery()
TransactionlessConnectionQuery()
)
我的集成测试被包装到事务中,以便在测试后回滚数据。
beginTransaction()
CodeExecution(
TransactionConnectionQuery()
TransactionlessConnectionQuery() // CONFLICT
)
rollBack()
我的解决方案是在那些测试中禁用包装事务,并以另一种方式重置数据库数据。