0

I have an InnoDB table in my MySQL which stores the current stock of a product, whenever a product is sold (always by the unit, i.e. always -1), the stock has to be updated by doing, let's say, something like:

UPDATE product_stock SET current_stock = current_stock -1 WHERE product_id = ?;

Now, I'm using Hibernate, so I'm updating the object ProductStock by setting the value of the currentStock attribute to "currentValue -1" like this:

instance.setCurrentStock(instance.getCurrentStock()-1);
...
session.saveOrUpdate(instance);

Now, I'm using transactions to commit the changes, however I'm not sure what will hibernate do when multiple sells are being made at the same time, and I haven't been able to successfully replicate the problem which I think will happen, that is, the current_stock won't be saved as current_stock -1 but as the value i setted to the object's instance attribute. e.g., I have 100, two transactions start at the same time to sell a product and both do in code

instance.setCurrentStock(instance.getCurrentStock()-1); 

setting both the stock to 99, then the transactions end and the current stock is saved to 99 when it should have been 98, am I right?

The question: Should/must I make an HQL statement to update the stock directly to -1 instead of updating the object's value from code?

UPDATE:

I was able to replicate the error by load testing the application with many users making a purchase at the same time, but what is actually happening is not that Hibernate is saving the stock wrong, what is happening is a deadlock at database level. We are currently working on it and the answers given are being very helpful.

The problem I'm now facing is that handling the locks might be tricky, because the current_stock table and specifically some rows of it might have many reads and many writes at the same time. I'll post the progress and hopefully the final solution

hectorg87
  • 753
  • 1
  • 7
  • 24
  • http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html#transactions-locking – aalku Nov 15 '13 at 12:41

2 Answers2

1

you have to try Optimistic-lock property of hibernate.

 <class name="pojofile" table="tablename" optimistic-lock="">      


</class>

you can see this link as well

Optimistic Locking in Hibernate by default

Community
  • 1
  • 1
Yogesh Soni
  • 272
  • 3
  • 9
1

I think your options are:

  1. Do as you suggest and decrement the stock level directly in the database with HQL. The disadvantage of this is that there is no guarantee the stock level won't go below zero if there are multiple simultaneous transactions!
  2. Use Hibernate's optimistic or pessimistic locking - there's lots of information in the documentation on this here.
  3. Ensure database updates can only occur from a single thread so transactions can't overlap.
ryanp
  • 4,905
  • 1
  • 30
  • 39
  • Thanks @ryanp, option 3 is out of the question, I need the concurrent updates. I'll check on option 2 which I think will solve the problem, if not, I'll use option 1 and deal with the problem of over-selling later. – hectorg87 Nov 15 '13 at 12:40
  • 1
    With option 1 you can use `where (...) and currentStock > 0 clause` that prevents over-selling and use the updated rows count to know if the action succeded or another user bought the last unit. – aalku Nov 15 '13 at 12:44