Use case is a Device sending JMS messages with GPS info processed by a MDB. If a Device doesnt exist then it is created/inserted and the GPS record created/inserted. Everything works fine when messages are handled as they are sent. The issue occurs when messages from the same device build up and are processed. The process is attempting to insert the Device entity multiple times because at some point the process finds no record exists but the following exception is thrown because the record has been inserted by a previous message being processed. I've tried changing the IsolationLevels to every value up to SERIALIZABLE with no luck. Any ideas would be much appreciated! WAS 7, OpenJPA 2.0.2, EJB3.0
[8/30/12 11:14:01:319 EDT] 0000002a RegisteredSyn E WTRN0074E: Exception caught from before_completion synchronization operation: <openjpa-2.0.2-SNAPSHOT-r422266:1295351 fatal store error> org.apache.openjpa.persistence.EntityExistsException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
Doing some testing i have found a decent work around though I'm still not 100% satisfied. Any other suggestions will be welcome:
- Set the JMS MDB in a Bean Managed transaction type and keep the other subsequent SSBs in Container mode so that I can still have the actual data operations Container managed for rollback.
- Set a programmatic threshold in the MDB to retry and process the message X amount of times.
- Catch the EJBTransactionRolledbackException (caused by the EntityExistsException) when the SSB is invoked
- Retry to process the message again using the threshold (in my case the second time was successful because the previous transaction was committed and the retry found that the entity exists and sucessfully processed the message)
- I set my threshold programatically to try and process the message twice before sending it to an error queue.
I don't normally like to use exception catching as a control flow. I also imagine there is a way to keep the JMS MDB as Container Managed transaction and have the J2EE server re-process the message...