hibernate transaction commit issue in high concurrency environment
I will explain my problem little bit in details. – i have following classes
- jms listener which will listen on a queue and will have java 1.5 thread pool executor to delegate the mssage to a thread(ie RequestExeuctor class).
- RequestExecutor(is a runnable class) which will process request by getting the servicelayer object
- service class(saveStudent(),getStudent())
- dao class.(saveStudent(),getStudent())
Consider the following scenario.
Request 1: jms message to save a student.
- jms received the msg and delegated to RequestExecutor to save the student.
- RequestExecutor call ServiceLayer.saveStudent() and sent messsage back to queue(here service layer has transaction boundary for all methods). so when message sent to queue,changes are not yet committed to db.
Request 2(this request will come with in some milliseconds): jms message to get the student.
- jms received the msg and delegated to RequestExecutor to getthe 开发者_如何学Cstudent(this is new thread).
- RequestExecutor call ServiceLayer.getStudent(), but here what ever changes done in first request not yet updated in db and returning null.
There is a some time gap(may be some milliseconds) between these two threads. but here i am able to see changes in db. but they are not visible to thread2.
Can some throw light on this problem.
Thanks, Ramki.
This is exactly these kinds of problems that 2 phase commit resolves. The write to the JMS queue and the save in the database should be part of the same global 2PC transaction, so that both are done, or none are done. This would guarantee that the second thread only received the JMS message if and only if the user has been saved in the database.
Java EE appservers provide XA-enabled (2 phase commit) transaction managers. If you're not running inside a Java EE appserver, you might sill integrate one yourself in the application, like Bitronix, Atomikos, or other stand-alone transaction managers.
Are this threads running on different JVM?
We've had similar problems when one process on a JVM commits a transaction to the database, and other process on another JVM not seeing the change because it is reading the value from it first or second level cache.
Sounds like you are using different resources (DB, JMS) to implement a business transaction, but don't synchronize the resource transactions, i.e. the JMS and DB transaction commit at different times, resulting in an inconsistent system state.
This is a standard architectural problem. Standard solutions include:
- Use xa-transactions. If you are running in an EJB container, container managed transactions will default to using xa-transactions (if the resources support xa-transactions). If you are not running in an EJB container, you can use a distributed transaction manager such as atomikos to leverage xa-transactions.
- Use only a single resource, either by
- only using a single transactional resource (the database, ditching JMS), or
- having the JMS implementation use the same database to persist messages. IIRC, if ActiveMQ is embedded into the VM, it can reuse the application's database connection to persist the JMS messages, thereby piggybacking on the database transaction.
精彩评论