I keep track of user credits in a creditlog table that looks like this:
user quantity action balance
1001     20     SEND   550
1001     30     SEND   520
1001     5      SEND   515
Now at first I tried to use Active Record syntax and select latest balance then insert a new line that computed the new balance. Then I found myself into a race condition:
user quantity action balance
1001     20     SEND   550
1001     30     SEND   520
1001     5      SEND   545 (the latest balance was not picked up because of a race condition)
Next solution was using a single query to do both:
INSERT INTO creditlog (action, quantity, balance, memberId) 
VALUES (:action, :quantity, (SELECT tc.balance from creditlog tc where tc.memberId=:memberId ORDER by tc.id desc limit 1) - :quantity, :memberId);
My script which tests this with 10 reqs/second would throw the following error for 2/10 queries:
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction. The SQL statement executed was:
INSERT INTO creditlog (action, quantity, reference, balance, memberId)     
VALUES (:action, :quantity, :reference, (SELECT balance from (SELECT tm.* FROM creditlog tm where tm.memberId=:memberId) tc where tc.memberId=:memberId ORDER by tc.id desc limit 1) -:quantity, :memberId, :recipientId);. 
Bound with  :action='send', :quantity='10', :reference='Testing:10', :memberId='10001043'.
Shouldn't the engine wait for the first operation to release the table then start on the second one?
Does my issue relate to: How to avoid mysql 'Deadlock found when trying to get lock; try restarting transaction' ?
How can I avoid this situation and turn the concurrent requests into sequential operations?
 
    