1205, ‘Lock wait timeout exceeded; try restarting transaction’

Recently we had an issue with very long-lived locks on certain rows in MySQL/MariaDB. Certain people (each row representing a person) would get locked out of updates for hours at a time. Using Flask/uWSGI/MariaDB/mysqldb.

SHOW ENGINE INNODB didn’t report any recent deadlocks or other issues but SHOW PROCESSLIST showed some very long sleeping processes and when these were killed the locks would go away. SELECT trx_started, trx_mysql_thread_id FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.id; was also interesting showing some unclosed transactiosn that corresponded.

We seem to have cleared the problem up by explicitly closing the database connection on teardown_request.

Atomic Transactional Replacement of a Table in MySQL

Even with AUTOCOMMIT off a DROP TABLE or CREATE TABLE statement will cause an implicit commit in MySQL.

So if you drop your table of (say) aggregated data and then create a new one even if you’re theoretically in a transaction there will be time when clients of the database see no table and time when they see an empty table.

The solution is to use RENAME TABLE.

CREATE TABLE replacement_table (...) AS SELECT ... FROM ...;
CREATE TABLE IF NOT EXISTS current_table (id INT); -- Just in case this is the first run and the table doesn't exist yet so RENAME TABLE doesn't fail.
RENAME TABLE current_table TO old_table, replacement_table TO current_table;

No client of the database will ever see a database that doesn’t contain an existing and populated current_table.