In the MySQL docs there is a statement I don't understand:
The correct way to use LOCK TABLES and UNLOCK TABLES with transactional tables, such as InnoDB tables, is to begin a transaction with SET autocommit = 0 (not START TRANSACTION) followed by LOCK TABLES, and to not call UNLOCK TABLES until you commit the transaction explicitly. (https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html)
Even after searching a lot in the docs and studying the description for "autocommit" and "START TRANSACTION", I really don't understand why to use autocommit instead of START TRANSACTION. Any ideas? Thanks
LOCK TABLES is not transaction-safe and implicitly commit any active transaction before attempting to lock the tables. Beginning a transaction, for instance, START TRANSACTION implicitly commits any current transaction and releases existing MySQL locks.
When auto-commit is disabled, you use a Connection object's commit and rollback methods to commit or roll back a transaction. The commit method makes permanent the changes resulting from the transaction and releases locks. The rollback method undoes all the changes resulting from the transaction and releases locks.
LOCK TABLES works as follows: Sort all tables to be locked in an internally defined order (from the user standpoint the order is undefined). If a table is locked with a read and a write lock, put the write lock before the read lock. Lock one table at a time until the thread gets all locks.
By default, MySQL runs with autocommit mode enabled. This means that as soon as you execute a statement that updates (modifies) a table, MySQL stores the update on disk to make it permanent. The change cannot be rolled back.
LOCK TABLES
implicitly commits a transaction, according to https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
So if you were to do the following sequence, it would not do what you intend:
BEGIN;
/* I think I'm in transaction 1 */
LOCK TABLES ...;
/* but that implicitly committed transaction 1 */
UPDATE blab blah ...;
/* I think I'm still in transaction 1, but this update caused
a new transaction 2 to begin and autocommit */
UPDATE yadda yadda ...;
/* I think I'm still in transaction 1, but this update caused
a new transaction 3 to begin and autocommit */
COMMIT;
The point of using transactions is when you need to run multiple updates, but you want the result of all updates to commit together or not at all.
The above example does not commit the two updates together atomically. They each have their own autocommitted transaction. Therefore one might succeed but the other doesn't.
The recommendation is to do the following:
SET autocommit=0;
LOCK TABLES ...;
/* that implicitly committed any outstanding transaction, but that's OK */
UPDATE blab blah ...;
/* because autocommit=0, a new DML statement implicitly starts a new transaction */
UPDATE yadda yadda ...;
/* the new transaction is still open */
COMMIT;
UNLOCK TABLES;
This commits both updates together, atomically.
Why not just LOCK TABLES and then BEGIN to start a transaction?
https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html says:
Beginning a transaction (for example, with START TRANSACTION) implicitly commits any current transaction and releases existing table locks.
That seems strange to me. An explicit BEGIN (or START TRANSACTION) releases table locks, but an implicit start of a transaction does not? That feature is full of WTF, in my opinion. But that's what's documented.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With