9

I want to lock a table inside a transaction. Something like this:

  DB::transaction(function (){
    DB::statement('LOCK TABLES important_table WRITE');
    //....
  });

However, the line DB::statement('LOCK TABLES important_table WRITE'); always triggers the following error:

SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. (SQL: LOCK TABLES officeSeal WRITE)

How can I lock the table in Laravel?

Adam
  • 25,960
  • 22
  • 158
  • 247
  • 1
    I wonder why you would need to lock a InnoDB table.. You really want InnoDB to behave like MyISAM? Besides using a TRANSACTION will lock the records needed. – Raymond Nijland Nov 28 '18 at 15:07
  • @RaymondNijland the reason why I need to lock a complete table can be found https://dba.stackexchange.com/questions/223608/using-transactions-without-select-for-update/223609 (see answer + comment) – Adam Nov 28 '18 at 15:09
  • Besides TRANSACTIONS in MySQL also supports transaction [isolation](https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html) also might be worth studing.. – Raymond Nijland Nov 28 '18 at 15:18
  • @RaymondNijland not sure if I understood you correctly - are you suggesting to copy the computed gaps in a temporary table? Because I compute the gaps in step 1, not in step 3. Sorry I am alittle confused. I read the section about transaction isolation. – Adam Nov 28 '18 at 15:33
  • Do _not_ use `LOCK TABLES` with InnoDB. – Rick James Nov 28 '18 at 19:54

4 Answers4

12

One can lock a table in Laravel like this:

DB::statement(DB::raw('LOCK TABLES important_table WRITE'));

However, you should be aware that locking a table is not very performant and row-locking should be used instead if possible.

Adam
  • 25,960
  • 22
  • 158
  • 247
4

As pointed out in the comments by other users too, I don't feel certain that a table lock is absolutely the only way out. However, if you insist, you could use Laravel's Pessimistic Locking. Namely, sharedLock() and lockForUpdate() methods, as mentioned in the documentation.

You'd notice that the example in the documentation doesn't use Eloquent, but relies on Query Builder. However, this Q&A seems to suggest that it can be done with Eloquent too.

It may also be worthwhile to have a read through this article which contrasts Pessimistic and Optimistic locking implementations in Laravel.

Dhruv Saxena
  • 1,336
  • 2
  • 12
  • 29
1

DB::unprepared('LOCK TABLES important_table WRITE'); this one worked for me

0
DB::statement(DB::raw('LOCK TABLES the_table WRITE'));
Sajjad
  • 430
  • 6
  • 17