• Post Reply Bookmark Topic Watch Topic
  • New Topic

static synchronized method in a StatelessSessionBean

 
Joe carco
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

I have a question about thread synchronization in StatelessSessionBean in JEE 5 (JBoss 5.1):

I have a stateless session bean with a method A that is called from a web application, triggered by a button click in a JSP. This method A checks the status of a specific entity bean B1. If it has the status "running" it throws an exception. If it doesn't have this status set, it sets it to "running" and and merges it via EntityManager. It then continues to perform alot if operations on this entity bean.

The problem is, that if 2 or more users simultaneously click on the button in the JSP, both get access to this entity bean becuase the method hasn't had a chance to merge the state of the entity bean to the database. So both clicks (threads) start to work with the entity bean resulting in a constraint violation exception, as this method A produces records B2 in a table with a composite primary keys (the composite primary key is generated depending on certain properties of the entity bean).

I "solved" this problem by delegating all the business logic to a static synchronied method, which obviously prevents multiple threads from simultaneously modifying any data on this entity bean. i.e. Method A calls Method B in the same stateless session bean (which is static synchronized) which does all the work that A did in a previous version.
It seems to work very well - even a junit test that hammers this method with 20 Threads at the same time was a succes.

Besides from this technique being a potential performance killer and a bottle neck, are there any obvious problems this could cause that I am overseeing? Is this allowed in a stateless session bean? Is there maybe a better ways of handling this?
Unfortunately changing the database structure or the way the primary keys are generated is not an option.
 
Paul Sturrock
Bartender
Posts: 10336
Eclipse IDE Hibernate Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, using thread synchronization to synchronize access with other enterprise bean instances is forbidden in the EJB spec. If you think about it, synchronizing access to anything in an EJB is kind of disingenious. Sounds like optimistic locking is probably what you might want to use instead.
 
Joe carco
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for your reply Paul.
I am using optimistic locking on my entities. It works fine when there is a even only slight delay between the requests from different User Sessions. However I managed to somehow bypass this in one of my tests by posting 2 requests absolutely simultaneously (almost down to the milisecond).
Maybe because the transaction in my SLSB is fairly large and 2 instances somehow manage to set and merge the entity with the state "runnning" at the same time?
 
Paul Sturrock
Bartender
Posts: 10336
Eclipse IDE Hibernate Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

However I managed to somehow bypass this in one of my tests by posting 2 requests absolutely simultaneously (almost down to the milisecond).
Maybe because the transaction in my SLSB is fairly large and 2 instances somehow manage to set and merge the entity with the state "runnning" at the same time

Are you using a timestamp as your versioning field? That is the only way this would be possible - though it might have to be to the millisecond (depending on the database and data type you've used). Better to use an integer and increment.
 
Joe carco
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No I am using version number (Integer) for optimistic locking

Maybe it is becuase the above mentioned business method A determines the status of the entity. If the status permits further operations it is set to "running" and is merged. After this in the same method a message is produced with the primary key of this entity and put in a queue. This queue only permits one message to be processed in an MDB at one time. only after the method returns does the SLSB with CMP commit the transaction. This means that the status is only really persisted once method A returns and therefore 2 transactions are more or less running at the same time, trying to process the same entity with the same status. 2 Messages are produced, one for each request / (instances of method A), and are executed in the MDB after each other with the same entity - which is not what I want because then I get a "Primary Key Constraint Error" from the DB - as descriped above.

Perhaps I should check the status in the onMessage() in the MDB and not in method A? Becuase the real "business" actually takes place in the MDB

So maybe I should always produce a message and send it to the queue regardless of the entites status, and only check the status in the onMessage(). I think this could work. Then I can remove my bad bad static synchronized method in the SLSB :-)
 
Paul Sturrock
Bartender
Posts: 10336
Eclipse IDE Hibernate Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

This means that the status is only really persisted once method A returns and therefore 2 transactions are more or less running at the same time, trying to process the same entity with the same status

Two transaction == two different values for your versioning field. You're not holding on to state in the SLSB too are you? Or running with read uncommited transaction isolation or soemthing?

Your idea to check in the MDB sounds like a better plan.
 
Rishi Shehrawat
Ranch Hand
Posts: 218
Hibernate Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I "solved" this problem by delegating all the business logic to a static synchronied method,

This approach will not work in a clustered environment.
 
Joe carco
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I finally figured it out - without any dirty tricks or workarounds I hope.
What i did was to load the entity via entitymanager in method A. Directly after that I say
after that I check and change the status, depending on status.
It seems that I had a "dirty-read" problem: 2 transactions reading the same entity, the one changing data and committing before the other one had comitted. as this transaction was a CMT it took a while before the updates were comitted by the container. In the mean-time a message was produced depending on the status of the entity.
I'm happy now :-)

 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!