I've started to play a little bit around with EJBs 3 some days ago. Things have seemed to be pretty straight-forward to me until I've stumbled accross the following problem with the transactions/isolation concept of EJB:
I have some kind of simple stateless session bean, like the following:
To summarize it up, I just want to read out the object with id 1 (which exists always in the db in this test-case), read out the value it has, increase the value by 1, and finally, write it back again into the db.
If I understand it correctly, I've defined with the code above a method which is transactional safe, because a new transaction will be created for every single method-call. Because I've also defined the datasource I'm using here as a "TRANSACTION_SERIALIZABLE" datasource, all calls to the method should be processed one after another. Am I right up to now?
The Entity POJO the Session Bean uses to read and write is also very simple. I've just post it for the purpose of completion:
OK, so far, so good. Next, I try to retrieve an instance of the remote-interface from a simple console-application. When I now use the method "incDBValue" within one client-thread, everything works fine. The value is increased by one.
But whenever I try to access the remote-interface concurrently (by doing some multithreading with my client-console-app) the behaviour of the method call is pretty unpredictable. For this test, I've used the following code:
Here I create 3 Threads, each trying to call the incDBValue-method. Running this programs leads to a non-deterministic result: sometimes I have a value of 18 in the table, sometimes more or less. But I will never have the value 30 (which should be in there after 30 successful calls of the incDBValue method).
For me, because of the ACID rules and the definition of the isolation level "TRANSACTION_SERIALIZABLE", it makes no sense that some updates on the values of the object are lost (especially without even receive some kind of exception). Normally, I would expect the following behaviour:
1.) Client1 enters the method incDBValue. A new transaction will be opened automatically by the app server 2.) Client1 retrieves the object it searches for. Because of the isolation level TRANSACTION_SERIALIZABLE this should trigger a write-lock, meaning that no other client, calling the same method, will have access to this object. 3.) Client2 tries to enter the method. A new transaction will be opened for it as well. 4.) Client2 tries to retrieve the same object Client1 has locked. Client2 will be put in a waiting-queue and can not process until Client1 has finished. 5.) Client1 has finished work after leaving the method. The transaction has been closed. 6.) Client2 sets now its write-lock on the object which was previously changed by client1. It can now work exclusively with the data. ...
If the mechanism worked like this, no update should be lost. But unfortunately it doesn't work like this so I seem to have some big misunderstanding concerning the transaction/isolation-handling of EJB :-(. Maybe someone can bring a little bit light into this matter? Would be great!