我有一个无状态EJB,它将数据插入数据库,立即发送响应,并在最后一步中调用异步EJB。异步EJB可以运行很长时间(我的意思是5到10分钟,这比JPA事务超时更长)。异步ejb需要读取(并对其进行处理)与无状态EJB所保留的记录树相同的记录树(仅读取)。
似乎异步bean在状态EJB提交或插入(JPA)之前尝试读取记录树,因此异步bean无法看到记录树。
无状态EJB:
@Stateless
public class ReceiverBean {
public void receiverOfIncomingRequest(data) {
long id = persistRequest(data);
sendResponseToJmsBasedOnIncomingData(data);
processorAsyncBean.calculate(id);
}
}
}
异步EJB:
@Stateless
public class ProcessorAsyncBean {
@Asynchronous
public void calculate(id) {
Data data = dao.getById(id); <- DATA IS ALLWAYS NULL HERE!
// the following method going to send
// data to external system via internet (TCP/IP)
Result result = doSomethingForLongWithData(data);
updateData(id, result);
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void updateData(id, result) {
dao.update(id, result);
}
也许我可以使用JMS队列向处理器bean发送ID为ID的信号,而不用调用asyc ejb(消息驱动的bean从数据库读取数据),但是如果可能的话,我想避免这种情况。
另一种解决方案可以是将整个记录树作为一个分离的JPA对象传递给处理器异步EJB,而不是从数据库中读回数据。
我可以以某种方式使异步EJB在这种结构中正常工作吗?
-更新-
我正在考虑使用Weblogic JMS。这里还有另一个问题。如果负载很大,当队列中有10万个或更多数据(这是正常的)并且没有Internet连接时,队列中的所有数据都将失败。如果在通过Internet(通过doSomethingForLongWithData
方法发送数据的过程中出现该异常(或任何异常),则数据将基于Weblogic的redelivery-limit
和repetitaion
设置回滚到原始队列。此回滚事件将在托管服务器上的Weblogic上生成100000或更多线程,以管理重新交付。大量新的后台进程可以杀死服务器,或至少使服务器变慢。
我也可以使用IBM MQ,因为我们拥有MQ基础结构。 MQ在Weblogic服务器上没有这种影响,但是MQ没有重新交付限制和延迟功能。因此,在发生错误(回滚)的情况下,消息将立即再次立即出现在MQ上,而不会出现延迟,因此我建立了手动铣床。我认为Thread.sleep()
条件下的catch
不是EE应用程序中的解决方案...
答案 0 :(得分:2)
似乎异步bean在状态EJB提交或插入(JPA)之前尝试读取记录树,因此异步bean无法看到记录树。
这是bean管理的事务的预期行为。您正在使用自己的事务上下文从EJB启动异步EJB。异步EJB从不使用调用者事务上下文(请参阅EJB规范4.5.3)。 只要您不使用具有持久性的“读取未提交”的事务隔离级别,就不会看到来自调用方的仍未提交的数据。
您必须考虑以下情况:什么时候取消提交作业(例如,应用程序服务器关闭或异常中止)。以下计算和更新是否至关重要?如果执行不成功或没有被调用,异步过程是否可以恢复?
您可以考虑使用bean管理的事务,在调用异步EJB之前提交。或者,您可以使用新的transactin上下文将数据更新委派给另一个EJB。这将在调用异步EJB之前提交。通常,对于不重要的内容,丢失或失败的情况,这都是可以的。
将持久性和事务性JMS消息与死信队列一起使用,具有可靠地计算和更新的优点,即使在过程之间停止/启动应用程序服务器或在处理过程中出现时间错误的情况下。
答案 1 :(得分:0)
您只需要在带有事务标记的方法旁边调用异步方法,以便在提交事务时使用。
例如,receiverOfIncomingRequest()方法的调用者可以添加
processorAsyncBean.calculate(id);
在它旁边打电话。
更新:扩展示例
CallerMDB
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void onMessage(Message message) {
long id = receiverBean.receiverOfIncomingRequest(data);
processorAsyncBean.calculate(id);
}
ReceiverBean
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public long receiverOfIncomingRequest(data) {
long id = persistRequest(data);
sendResponseToJmsBasedOnIncomingData(data);
return id;
}