1
|
I have an ordering platform on a remote webserver and a local production machine here at my office. Both webservers access the same remote MySQL (InnoDB) database.
My Problem: The production takes several minutes in which 2-3 transactions are open. In this time I generate new invoice numbers and increment them. The most recent invoice number is saved in a Numbers-Table on the database.
Now when someone is saving a new order during the production they are accessing the same Numbers-Table to generate another number (not the invoice). All the orders processed by the production are saved with the correct invoice numbers. However, the Numbers-Table isn't updated with the newest value and the invoice number remains the same as before the production.
I understand that one of the transaction gets a "stale table" message. But what is the behavior of MySQL / Hibernate / Java? I'd like to get an exception from one of the transactions so I can rollback and don't have this dangerous database inconsistency.
EDIT : This is how the table
Numbers looks like:
id is the primary key. I only access this one row and increase the needed number.
EDIT 2 : Okey, I see that this table structure is kinda bad. I updated it to:
Now I can access each row independently. Don't know if that solves my problem though.
| ||||||||||||
|
0
|
You must use InnoDB if using MySQL, you should ensure Hibernate is adding the "FOR UPDATE" to the SQL generated for the
crit.uniqueResult() part. I would also set a Java breakpoint just after (to stop execution) and manually test the same SQL query causes another client to block.
This is more to test your SQL server is sane and your Dialect is setup correctly and basically the feature works for you.
This forces serialization at the SQL server in the generation of the next InvoiceNumber.
This way you never get 2 InvoiceNumber the same even if 1000 users simultaneously try to make invoices.
NOTE: LockOptions replaces the LockMode to specify mode things about this aspect of concurrency. See the hibernate release notes for help.
NOTE: You talked of transactions lasting minutes. While the transaction is not committed no other user can generate a new invoice number. Maybe you need to run this as a nested and separate transaction. Then you have the problem holes appearing in InvoiceNumber's if there is a failure to use the number due to some other processing error. Accountants / accounting systems don't like holes in invoice numbers, nor them being out of date sequence.
Related MySQL documentation link https://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
| |||
add comment |
0
|
There are different ways to concurrently work with the database, for instance using Optimistic lock or Pessimistic one (you should be careful with the latter since it may cause delays and dead locks).
But I guess in your case you have to change the Numbers table right after some transaction starts, not by the end of it. This would ensure that the slot for the invoice is reserved.
Also makes sense to look at the Id Generators of the Hibernate, you can see there different ideas of how to implement value-generating mechanisms.
| |||
add comment |