1

使用 EJB 3.0,两个线程将尝试运行此代码(即在无状态会话 bean 中)。两个线程都能够通过 if 语句并打印出该语句。

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();

我尝试将事务隔离级别设置为可序列化但没有成功:

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

也许我使用了错误的方法。

更新

不能使用 Singleton 会话 bean,因为 Jboss 5 不支持它们。现在我正在尝试以下代码来解决我在其他时候遇到死锁的问题:

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();
4

1 回答 1

0

您可以将相关代码或整个方法转移到单例会话 bean 并应用适当的锁定策略。

以下是文档的一些摘录,它们将更详细地阐明它。

  • 如果单例使用容器管理的并发,则 EJB 容器控制客户端对单例的业务方法的访问

  • 如果在客户端调用该方法时单例会话 bean 应锁定到其他客户端,则使用 @Lock(LockType.WRITE) 注释业务或超时方法。通常,当客户端修改单例的状态时,会使用 @Lock(LockType.WRITE) 注释。

  • 如果单例类上没有 @Lock 注释,则默认锁定类型 @Lock(LockType.WRITE) 将应用于所有业务和超时方法。


编辑:作为一种解决方法,您可以拥有一个池大小为 1 的无状态会话 bean。使用@Poolbean 上的注释或通过 xml 配置指定它。

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

有关详细信息,请参阅此处,这是特定于 JBoss 的,但可以针对其他服务器以不同方式实现。

于 2013-08-22T07:56:17.947 回答