0

I'm still confused about table row locking. I'm using MySQL/PHP and here is my scenario.

I have a set of tables that my application uses to keep track of requests and posts. A user creates a posting (table POSTING (P)) for an item (table ITEM (I)) and can send out requests to individual users (table REQUEST (R)) or can post it and receive post responses (table POSTING_RESPONSE (PR)) that will be accepted by user posting item.

Example: I am a user with a bike. I post it - and also send out requests to individual users. The users that receive the request from me can accept / reject / or do nothing. If they accept - it is reserved. Other users can find my posting and 'apply' for item. I have the ability to 'accept' or 'ignore' their request. If I accept, Item is reserved.

What I want to do if someone accepts request:

  1. lock row in ITEM (I) table corresponding to item

  2. lock row in POSTING (P) table (if row exists) corresponding to the item

  3. lock row(s) in REQUEST (R) table for any requests sent for item

  4. lock row(s) in POSTING_RESPONSE (PR) table (if rows exist) corresponding to item

  5. update ITEM status to 'Reserved'

  6. update POSTING status to 'Unavailable'

  7. update all/any POSTING_RESPONSE to 'Rejected'

  8. update all REQUEST to 'Rejected' besides the one that has accepted - update that one to 'Accepted'

Ignore the redundancy of status with this example please.

Now, I assumed that #1 - 4 could be done with a simiple "select ... for update" leaving AUTOCOMMIT as false. I could deterime with these select statements whether or not I should update - and if so, I can continue to the updates. Then after completion of updates #5-8, I would commit and rows would be unlocked.

I'm having problems getting this to work, and I don't know if it is because of something I'm doing or my thinking is incorrect.

One more thing... there are other processes that can update the status of the item to, say, EXPIRED or CANCELLED. I'm hoping that the only solution to my approach isn't to put every single possible condition in a WHERE clause within UPDATE statements... this would not be easily maintainable.

NEW2WEB
  • 503
  • 2
  • 8
  • 22
  • 1
    Typically SELECT's are reads that are non-locking. To lock a SELECT you have to specify [locking reads](http://dev.mysql.com/doc/refman/5.6/en/innodb-locking-reads.html) – Jay Blanchard Oct 30 '14 at 18:14
  • @JayBlanchard, can you explain? Maybe I'm just thick, but I've looked at your referece before and from what I gathered there are only two options: LOCK IN SHARE MODE - which won't prevent reads - and FOR UPDATE - which is what my example above shows. Does FOR UPDATE not work in my example above? If not, what should it be?? – NEW2WEB Oct 30 '14 at 18:32
  • No, I just missed reading that. What is not working for you? – Jay Blanchard Oct 30 '14 at 18:34

1 Answers1

0

Mini-transaction: do it in one query.

UPDATE item
LEFT JOIN posting
   ON posting.item_id = item.id -- or however
LEFT JOIN request 
   ON request.item_id = item.id -- or however
LEFT JOIN posting_reponse
   ON posting_response.item_id = item.id 
SET 
   item.status = 'Reserved',
   posting.status = 'Unavailable',
   posting_reponse.status = 'Rejected',
   request.status = IF(request.id = some-current-id,'Accepted','Rejected')
WHERE item.id = some-id AND item.status='Available';

... and stop asking questions about locking for read, you really don't want that :P

Wrikken
  • 69,272
  • 8
  • 97
  • 136
  • Wrikken - this is probably the way to go, but I still don't get what is wrong with locking for read? – NEW2WEB Oct 30 '14 at 18:40
  • If you say: 'no other process may read this data', they will not ignore this data, but processes will hang until the data becomes available. While that works ok-ish on very low traffic projects, it does not scale beyond a few visitors: any moderately active project will grind to a halt with all kinds of (sub)processes / requests waiting for others. Requests take more and more time as traffic increases, and you reach the point where lock-timeout errors occur. You could increase that timeout, but nobody would use your project anymore if they have to wait for > a minute for anything to happen. – Wrikken Oct 30 '14 at 18:54