In my production error logs I occasionally see:
SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction
>
Due to the popularity of MySQL, there's no wonder Lock wait timeout exceeded; try restarting transaction exception gets so much attention on SO.
The more contention you have, the greater the chance of deadlocks, which a DB engine will resolve by time-outing one of the deadlocked transactions. Also, long-running transactions that have modified (e.g. UPDATE
or DELETE
) a large number of entries (which take locks to avoid dirty-write anomalies as explained in the High-Performance Java Persistence book) are more likely to generate conflicts with other transactions.
Although InnoDB MVCC, you can still request explicit locks using the FOR UPDATE clause. However, unlike other popular DBs (Oracle, MSSQL, PostgreSQL, DB2), MySQL uses REPEATABLE_READ as the default isolation level.
Now, the locks that you acquired (either by modifying rows or using explicit locking), are held for the duration of the currently running transaction. If you want a good explanation of the difference between REPEATABLE_READ
and READ COMMITTED
in regards to locking, please read this Percona article.
In REPEATABLE READ every lock acquired during a transaction is held for the duration of the transaction.
In READ COMMITTED the locks that did not match the scan are released after the STATEMENT completes.
...
This means that in READ COMMITTED other transactions are free to update rows that they would not have been able to update (in REPEATABLE READ) once the UPDATE statement completes.
Therefore: The more restrictive the isolation level (REPEATABLE_READ
, SERIALIZABLE
) the greater the chance of deadlock. This is not an issue "per se", it's a trade-off.
You can get very good results with READ_COMMITED
, as you need application-level lost update prevention when using logical transactions that span over multiple HTTP requests. The optimistic locking approach targets lost updates that might happen even if you use the SERIALIZABLE isolation level while reducing the lock contention by allowing you to use READ_COMMITED
.