Java 在单独的EJB方法中启动/结束事务
我开发了一个典型的企业应用程序,负责将客户配置到第三方系统。该系统有一个限制,即只有一个线程可以在某个客户上工作。因此,我们添加了一个简单的锁定机制,它由Java 在单独的EJB方法中启动/结束事务,java,database,ejb,cluster-computing,bean-managed-transactions,Java,Database,Ejb,Cluster Computing,Bean Managed Transactions,我开发了一个典型的企业应用程序,负责将客户配置到第三方系统。该系统有一个限制,即只有一个线程可以在某个客户上工作。因此,我们添加了一个简单的锁定机制,它由@Singleton组成,其中包含当前正在进行的客户ID集。每当有新的资源调配请求出现时,它都会首先检查此集。如果cusotomerId存在,它将等待,否则它会将其添加到集合并进入处理 最近决定将此应用程序部署在集群中,这意味着此锁定方法不再有效。我们提出了一个使用DB进行锁定的解决方案。我们创建了一个包含CustomerID的单列表(它还有一
@Singleton
组成,其中包含当前正在进行的客户ID集。每当有新的资源调配请求出现时,它都会首先检查此集
。如果cusotomerId存在,它将等待,否则它会将其添加到集合
并进入处理
最近决定将此应用程序部署在集群中,这意味着此锁定方法不再有效。我们提出了一个使用DB进行锁定的解决方案。我们创建了一个包含CustomerID的单列表(它还有一个唯一的约束)。当一个新的配置请求到来时,我们启动一个事务,并尝试用选择更新锁定customerId行(如果customerId尚不存在,则插入它)。在这之后,我们开始为客户配置,完成后,我们提交事务。
概念可行,但我在交易方面有问题。目前,我们有一个类CustomerLock
,其中包含add()
和remove()
方法,用于在集合中添加和删除customerID。我想将这个类转换成一个具有bean管理事务的无状态EJBadd()
方法将启动事务并锁定行,而remove()
方法将提交事务并因此解锁行。但似乎事务的开始和结束必须以相同的方法进行。是否有一种方法可以使用我描述的方法,或者我必须修改逻辑以便事务以相同的方法开始和结束
CustomerLock类别:
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CustomerLock {
@Resource
private UserTransaction tx;
public void add(String customerId) throws Exception {
try {
tx.begin();
dsApi.lock()
} catch (Exception e) {
throw e;
}
}
public void remove(String customerId) throws Exception {
try {
tx.commit();
} catch (Exception e) {
throw e
}
}
}
CustomerProvisioner类摘录:
public abstract class CustomerProvisioner {
...
public void execute(String customerId) {
try {
customerLock.add(customerId);
processing....
customerLock.remove(customerId);
} catch (Exception e) {
logger.error("Error", e);
}
}
...
}
StandardCustomerProvisioner类别:
@Stateless
public class StandardCustomerProvisioner extends CustomerProvisioner {
...
public void provision(String customerId) {
// do some business logic
super.execute(customerId);
}
}
正如@Gimby所指出的,您不应该混合使用容器管理的事务和bean管理的事务。由于您的StandardCustomerProvision没有类似“@TransactionManagement(TransactionManagementType.BEAN)”的注释,因此它使用容器管理的事务,并且默认情况下是必需的
您有两个选项可以让它工作:
1) 要删除带有UserTransaction调用的“@TransactionManagement(TransactionManagementType.BEAN)”并运行CMT
2) 将此注释(@TransactionManagement(TransactionManagementType.BEAN)”添加到StandardCustomerProvisioner并使用此方法的事务标记调用,以便所有调用的方法使用相同的事务上下文。无论如何都应该删除来自CustomerLock的标记调用。为什么您认为“事务的开始和结束必须在同一个方法中发生”?在finally block BTW中有一个非常奇怪的提交调用。当一切正常时(没有抛出异常),它将提交事务,DB锁将消失(它是事务范围的)。抱歉。。。“finally”没有出现:)我更正了代码。这些代码通常不够详细。什么是“客户提供”?另一个EJB?它有点“扭曲”,但从技术上讲是的。再详细一点。。。我们有三个CustomerProvisioning抽象类的实现。现在我唯一能看到的是容器管理的事务和bean管理的事务混合在一起,但我根本看不到它们是如何连接在一起的。很抱歉,响应太晚了。。。是的,我完全误解了这个事务在容器中的工作方式。只有在几句评论之后,我才开始思考如何实现上述解决方案。我想我只是需要一点“头脑风暴”:)谢谢大家的回复!干杯