1

I'm stuck with this. To make it simpler, let's say I have this table

CREATE TABLE IF NOT EXISTS `tbl_bags_oranges` (
  `idbag` int(11) NOT NULL AUTO_INCREMENT,
  `n_oranges` int(11) NOT NULL,
  PRIMARY KEY (`idbag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci AUTO_INCREMENT=1 ;

And I'm developing a php script that represents the situation in which users grab oranges. This is what I'm doing:

  1. I use a SELECT to check if there are oranges in the given idgab (n_oranges > 0)
  2. If so, I UPDATE the table subtracting 1 to n_oranges

But it may happen the following when there is just one orange in a bag:

  1. User A wants to grab an orange. The ´SELECT´ says there is one orange.
  2. User B wants to grab an orange. The ´SELECT´ says there is one orange.
  3. User A grab the orange. I UPDATE the table and now n_oranges = 0.
  4. User B is able to grab the orange because his SELECT said that there was one orange.

How can I solve this question? Transactions? LOCK TABLES? Since I can't check this situation there is no way to know if I'm doing well or wrong.

DandyCC
  • 353
  • 1
  • 6
  • 20

2 Answers2

0

You can do a checking when you update the table something like this:

UPDATE `tbl_bags_oranges`
SET n_oranges=n_oranges-1 
WHERE n_oranges>=1;

You may modify the code based on your situation.

Herris
  • 61
  • 5
  • Sorry, my fault. I wanted the question to be as simpler as possible to made it clear and I didn’t realize that my example was too much simple. Actually I have to check values from 3 different tables and then update one of them. – DandyCC Jul 19 '16 at 13:29
0

You can use locking reads. In detail:

  • make sure autocommit is disabled
  • START TRANSACTION
  • SELECT ... FROM tbl_bags_oranges WHERE ... FOR UPDATE
  • do whatever else you need to do in your code
  • save the new valueUPDATE tbl_bags_oranges SET ...
  • COMMIT

In this case in your scenario the second query would block until the first transaction commits hence no race condition would occur

Oleg Kuralenko
  • 11,003
  • 1
  • 30
  • 40