使用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();
答案 0 :(得分:0)
您可以将相关代码或整个方法转移到Singleton会话bean&适用适当的锁定策略。
以下是文档中的一些摘录,将更详细地阐明它。
如果单例使用容器管理的并发,则EJB容器控制客户端对该业务方法的访问 单
如果单个会话bean应该锁定到其他客户端,请使用@Lock(LockType.WRITE)注释业务或超时方法 而客户端正在调用该方法。通常, 客户端修改时使用@Lock(LockType.WRITE)注释 单身人士的状态。
如果单例类中没有@Lock注释,则默认锁定类型@Lock(LockType.WRITE)将应用于所有 业务和超时方法。
编辑:作为一种变通方法,您可以拥有一个池大小为1的无状态会话bean。使用bean上的@Pool
注释或通过xml配置指定它。
@Pool(value=PoolDefaults.POOL_IMPLEMENTATION_STRICTMAX,maxSize=1,timeout=5000)
有关详细信息,请参阅here,这是JBoss特有的,但可以以不同方式为其他服务器实现。