Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL: LOCK TABLES with autocommit vs. START TRANSACTION

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

like image 386
Anumi Avatar asked May 26 '18 06:05

Anumi


People also ask

Do transactions lock tables MySQL?

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.

What happens when autocommit is set off?

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.

How do I lock a table in MySQL?

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.

Does autocommit ROLLBACK?

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.


1 Answers

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.

like image 97
Bill Karwin Avatar answered Sep 18 '22 22:09

Bill Karwin