Nov 22nd, 2010, 10:31 AM
EJB, REQUIRES_NEW and Persistence Context
I'm using JBoss 5.1.0 together with Spring 2.5.6 and Spring transaction demarcation via annotations on EJBs.
We have EJB A and B. A has a method with default propagation REQUIRED that calls method B with propagation REQUIRES_NEW on EJB B.
Method B creates an entity and puts a message on a JMS queue in one, isolated tx. That means either entity creation _and_ message creation both works or neither of them.
After method B is left, and entity and message were created successfully (tx is comitted), method A waits for a response on the JMS queue. When it receives the response, I would like to refresh the state of the entity created by the REQUIRES_NEW method B of EJB B. This is because the entity could have been modified by components on the other queue endpoint.
This works most of the time without a problem. But when I create load on the system, it happens, that on method A I can't refresh or even find the entity created by method B. I guess this is because of the two different PersistentContexts used by A and B - due to REQUIRES_NEW on B. But why the hell does this only happen under load? It seems that this has something todo with creating new connections. I tried it with 10 threads a 10 requests. Then it failed to find the entity in some cases. I restarted the test and then everything worked. I re-ran the test with 20 theads a 10 requests and the error occurred again. After a 2nd run everything worked. So, like I said, when it comes to additional connection creation (the builtin JBoss pool is maxed for 100 connections) something goes wrong. I have no clue where that happens. Maybe others have?
What is the common way to handle such a scenario described above? How can I _reliably_ find() my entity in A that was created in B? Tried isolation level READ_UNCOMITTED in A, but that didn't work out.
Any hints or clue what goes wrong?
Nov 23rd, 2010, 03:49 AM
Meanwhile we found the cause of the problem.
It seems, that mysql 5.1 together with innoDB has the default isolation level of REPEATABLE_READ not READ_COMMITTED as expected. Since we didn't set an explicit isolation level on jboss datasource xml nor EJB level it was used as default. Setting it to READ_COMMITTED in the datasource xml explicitly, solves our problem.
What is left is, why this behavior only occurs on new connections and not already established ones from the pool. My guess is that somewhere the isolation level is explicitly set to READ_COMMITTED and overrides the mysql default one. After that the pooled connection is then READ_COMMITTED and behaves as expected. Only new connections cause problems as they are REPEATABLE_READ - until they get switched to READ_COMITTED somewhere. I don't know if JBoss or Spring does this. In our code there's no explicit isolation level set