Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

creativeorange's avatar

Lock tables in Eloquent / DB

I'm building an app where users can place bids on certain products in an auction. You always have to place a bid at least € 1,00 higher than the previous bid.

The PHP workflow:

  • Fill form with bid
  • Form request validates the bid (check if high enough)
  • Eloquent save
  • Redirect to auction page with succes or error notification.

Between step 2 and 3 there is a execution time gap of a few milliseconds. So in theory, users can place the same bid if they do it on exactly the same time. To prevent that, I have to lock the table before step 2 and release the lock after step 3.

So, my question is: Does anyone has any experience in locking tables (preferable in combination with Eloquent)? And how would you solve this?

N.B.: I haven't written any code for this (yet).

0 likes
15 replies
bestmomo's avatar
Level 52

I suppose you have an unique index in table so if the same bid is to be saved (really a rare case) you'll get a PDO error that you can manage.

1 like
creativeorange's avatar

@bestmomo Interesting. Haven't thought of that. This actually might be a more elegant solution for this particular problem.

pmall's avatar

@creativeorange db transactions are made for this :

DB::transaction(function ($bid_value) {

    // Get $max_bid

    // If $bid_value > $max_bid then save the bid

    // If $bid_value <= $max_value then throw an exception

});

Db transactions are atomic operations at db level.

2 likes
bestmomo's avatar

@codeatbusiness "Locking is required only when developing scripts that first read a value from a database and later write that value to the database."

@pmall I dont see how transaction avoid this issue.

2 likes
creativeorange's avatar

Thanks for all the replies, guys! Although @bestmomo his first answer solved my particular problem, it didn't actually answer my initial question: How to lock a table for the lifetime of a request?

@codeatbusiness thanks for the links to the source code. It's good to know there are possibilities in Laravel's codebase to solve my problem. However, I'm not quite sure how to implement this.

@SachinAgarwal I did read this in the documentation. But I think it's not that clear how to use pessimistic locking. If I use sharedLock or lockForUpdate, what does it do? Do I have to unlock lockForUpdate after all my queries are finished? And what does sharedLock mean?

@pmall thanks for the DB::transaction method, I think this might be a possible way to go about it. But after @bestmomo's reply "I dont see how transaction avoid this issue.", I'm not sure if I could use transactions. @bestmomo : could you explain why this solution doesn't avoid this issue?

A long story short: How do I lock a table for writing until the first user completed his bid? Or: How do I prevent a second user for executing his read and write request to the database before the first user's request is finished?

SachinAgarwal's avatar

@creativeorange Sorry, My bad, you cannot lock table for writing with pessimistic lock. You can lock only for reading and updating.
@bestmomo gave you the answer. I would suggest the same as you will have a time gap. its very rare case when 2 transactions take place at same time. :)

creativeorange's avatar

Okay, to recapulate: I have three (maybe more) options.

  1. The solution @bestmomo gave me (and the one I will use). In my schema: $table->unique(['auction_id', 'amount']);
  2. Lock the table, execute the READ and WRITE queries and unlock the table. After doing some more research very many developers, among @jimmck, advice against this solution. Especially because other parts of my application use this table as well.
  3. Writing a stored procedure. This might be a good solution as well, but I think a stored procedure would be a bit overkill.

Thanks @bestmomo, @SachinAgarwal, @jimmck and @codeatbusiness for all the replies and the effort you guys put in answering my question.

jimmck's avatar

I humbly believe you will find the unique index solution to make your very slow as the number of bids per item increase. The cost of scanning the index on each insert plus the handing of the error can be prohibitive. Also many developers are taught not to rely on Exceptions and system error handling as a means of process control. See Josh Bloch author of Effective Java. I know its PHP, but good design is language agnostic. Not to trumpet my idea over others, but database Stored procedures are bread & butter tasks in day to day DB coding. Databases today provide ample tools to solve concurrency issues. Which begs the question what database aren you using? Jim

creativeorange's avatar

Thanks @jimmck! I really appreciate your reply. You convinced me to take stored procedures under consideration and I will try this out next monday. I will post my code here.

Please or to participate in this conversation.