Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PDO, mysql, transactions and table locking

For fun I am replacing the mysqli extension in my app with PDO.

Once in awhile I need to use transactions + table locking.

In these situations, according to the mysql manual, the syntax needs to be a bit different. Instead of calling START TRANSACTION, you do it like so...

SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;

(http://dev.mysql.com/doc/refman/5.0/en/lock-tables-and-transactions.html)

My question is, how does this interact with PDO::beginTransaction? Can I use PDO::beginTransaction in this case? Or should I manually send the sql "SET autocommit = 0; ... etc".

Thanks for the advice,

like image 938
Travis Avatar asked Jun 24 '10 01:06

Travis


People also ask

Do transactions lock tables MySQL?

LOCK TABLES and UNLOCK TABLES interact with the use of transactions as follows: LOCK TABLES is not transaction-safe and implicitly commits any active transaction before attempting to lock the tables. UNLOCK TABLES implicitly commits any active transaction, but only if LOCK TABLES has been used to acquire table locks.

Does @transactional lock table?

FOR UPDATE or SELECT ... LOCK IN SHARE MODE inside a transaction, as you said, since normally SELECTs, no matter whether they are in a transaction or not, will not lock a table.

How do I stop a MySQL table from locking?

Third option to prevent table locks with MySQL database is to use AUTOCOMMIT on the database level. This will prevent table locks from occurring unintentionally during report execution since all the transactions are committed after they are executed without additional commit commands.

What is table level locking in MySQL?

MySQL uses table-level locking for MyISAM , MEMORY , and MERGE tables, permitting only one session to update those tables at a time. This locking level makes these storage engines more suitable for read-only, read-mostly, or single-user applications.


2 Answers

When you call PDO::beginTransaction(), it turns off auto commit.

So you can do:

$db->beginTransaction();
$db->exec('LOCK TABLES t1, t2, ...');
# do something with tables
$db->commit();
$db->exec('UNLOCK TABLES');

After a commit() or rollBack(), the database will be back in auto commit mode.

like image 180
Olhovsky Avatar answered Sep 28 '22 04:09

Olhovsky


I have spent a huge amount of time running around this issue, and the PHP documentation in this area is vague at best. A few things I have found, running PHP 7 with a MySQL InnoDB table:

PDO::beginTransaction doesn't just turn off autocommit, having tested the answer provided by Olhovsky with code that fails, rollbacks do not work; there is no transactional behaviour. This means it can't be this simple.

Beginning a transaction may be locking the used tables... I eagerly await for someone to tell me I'm wrong with this, but here are the reasons it could be: This comment, which shows a table being inaccessible when a transaction has started, without being locked. This PHP documentation page, that slips in on the end:

... while the transaction is active, you are guaranteed that no one else can make changes while you are in the middle of your work

To me this behaviour is quite smart, and also provides enough wiggle room for PDO to cope with every database, which is after all the aim. If this is what is going on though, its just massively under documented and should've been called something else to avoid confusion with a true database transaction, which doesn't imply locking.

Charles' answer I think is probably the best if you are after certainty with a workload that will require high concurrency; do it by hand using explicit queries to the database, then you can go by the database's documentation.

Update I have had a production server up and running using the PDO transaction functions for a while now, recently using AWS's Aurora database (fully compatible with MySQL but built to automatically scale etc). I have proven these two points to myself:

  • Transactions (purely the ability to commit all database changes together) work using PDO::beginTransaction(). In short, I know many scripts have failed half way through their database select/updates and data integrity has been maintained.
  • Table locking isn't happening, I've had an index duplication error to prove this.

So, to further my conclusion, looks like the behaviour of these functions seems to change based on database engine (and possibly other factors). As far as I can tell both from experience and the documentation, there is no way to know programmatically what is going on... whoop...

like image 35
Jamie Robinson Avatar answered Sep 28 '22 02:09

Jamie Robinson