Domanda

Using EJB 3.0, two threads will try to run this code (that is inside a stateless session bean). Both threads are able to pass through the if statement and print out the statement.

userTransaction.begin(); //userTransaction is of class UserTransaction
myEntity = entityManager.find(MyEntity.class, id); //entityManager is of class EntityManager
if (myEntity.getStatus() != "DONE") {
    myEntity.setStatus("DONE");
    entityManager.merge(myEntity);
    System.out.println("Only one thread should be running this");
}
userTransaction.commit();

I've tried setting the transaction isolation level to serializable with no success:

org.hibernate.Session session = (org.hibernate.Session) entityManager.getDelegate();
session.connection().setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

Maybe I'm using the wrong approach.

UPDATE

Cannot use Singleton session beans because Jboss 5 does't support them. Right now I'm trying the following code with the problem that I run into deadlock some other time:

connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
connection.setAutoCommit(false);

//selectStatement and updateStatement are of type PreparedStatement
selectStatement = connection.prepareStatement("SELECT STATUS FROM MYTABLE WHERE STATUS != 'DONE' AND ID=?");
selectStatement.setInt(1, id);

updateStatement = connection.prepareStatement("UPDATE MYTABLE SET STATUS = 'DONE' WHERE ID=?");
updateStatement.setInt(1, id);

resultSet = selectStatement.executeQuery();
if (resultSet.next()) {
   updateStatement.executeUpdate();
}
connection.commit();
È stato utile?

Soluzione

You can shift the relevant code or the entire method to a Singleton session bean & apply appropriate locking strategy.

Below are few excerpts from the documentation which will clarify it in more detail.

  • If a singleton uses container-managed concurrency, the EJB container controls client access to the business methods of the singleton

  • Annotate the business or timeout method with @Lock(LockType.WRITE) if the singleton session bean should be locked to other clients while a client is calling that method. Typically, the @Lock(LockType.WRITE) annotation is used when clients are modifying the state of the singleton.

  • If no @Lock annotation is present on the singleton class, the default lock type, @Lock(LockType.WRITE), is applied to all business and timeout methods.


Edit : As a workaround, you can have a stateless session bean with pool size as 1. Specify it with the @Pool annotation on bean or through xml configuration.

@Pool(value=PoolDefaults.POOL_IMPLEMENTATION_STRICTMAX,maxSize=1,timeout=5000)

Refer here for more details, this is JBoss specific, but can be implemented for other servers differently.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top