@Stateless 和@Asynchronous EJB 之间的 JPA 事务处理
JPA transaction handling between @Stateless and @Asynchronous EJBs
我有一个无状态 EJB,它将数据插入数据库,立即发送响应,并在最后一步调用异步 EJB。异步 EJB 可以 运行 很长时间(我的意思是 5-10 分钟,比 JPA 事务超时时间长)。异步 ejb 需要读取(并处理它)与无状态 EJB 持久化的记录树相同的记录树(仅读取)。
异步 bean 似乎在记录树被 statelsss 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 队列将带有 ID 的信号发送到处理器 bean,而不是调用 asyc ejb(和消息驱动的 bean 从数据库读取数据),但我想尽可能避免这种情况。
另一种解决方案是将整个记录树作为分离的 JPA 对象传递给处理器异步 EJB,而不是从数据库中读回数据。
我能否以某种方式使异步 EJB 在此结构中正常工作?
--更新--
我正在考虑使用 Weblogic JMS。这里还有一个问题。在大负载的情况下,当队列中有 100 000 个或更多数据(这将是正常的)并且没有互联网连接时,队列中的所有数据都将失败。如果在通过 Internet 发送数据(通过 doSomethingForLongWithData
方法)期间出现该异常(或任何异常),数据将根据 Weblogic 的 redelivery-limit
和 repetitaion
设置回滚到原始队列.此回滚事件将在托管服务器中的 Weblogic 上生成 100 000 个或更多线程来管理重新交付。新的大量后台进程可以杀死或至少减慢服务器速度。
我也可以使用 IBM MQ,因为我们有 MQ 基础设施。 MQ对Weblogic服务器没有这种影响,但是MQ没有redelivery-limit和delay功能。因此,如果出现错误(回滚),消息将立即再次出现在 MQ 上,没有延迟,我构建了一个手磨机。 Thread.sleep()
在 catch
条件下我猜想在 EE 应用程序中不是解决方案...
Is seems that the asynchronous bean tries to read the record tree before it was commited or inserted (JPA) by the statelsss EJB so record tree is not visible by async bean.
这是 bean 管理事务的预期行为。您正在从具有自己的事务上下文的 EJB 启动异步 EJB。异步 EJB 从不使用调用者事务上下文(参见 EJB 规范 4.5.3)。
只要您没有在持久性中使用事务隔离级别 "read uncommited",您就不会看到调用者仍未提交的数据。
你必须考虑这种情况,当异步作业不会提交时(例如应用程序服务器关闭或异常中止)。以下计算和更新是否重要?异步过程执行不成功或者连调用都没有调用是否可以恢复?
您可以考虑使用 bean 管理的事务,在调用异步 EJB 之前提交。或者,您可以将数据更新委托给具有新事务处理上下文的另一个 EJB。这将在调用异步 EJB 之前提交。这通常适用于不重要的东西,丢失或失败。
使用持久性和事务性 JMS 消息以及死信队列具有可靠处理计算和更新的优势,即使在中间停止/启动应用程序服务器或在处理期间出现临时错误也是如此。
您只需要在带有事务标记的方法旁边调用异步方法,以便在提交事务时调用。
例如,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;
}
我有一个无状态 EJB,它将数据插入数据库,立即发送响应,并在最后一步调用异步 EJB。异步 EJB 可以 运行 很长时间(我的意思是 5-10 分钟,比 JPA 事务超时时间长)。异步 ejb 需要读取(并处理它)与无状态 EJB 持久化的记录树相同的记录树(仅读取)。
异步 bean 似乎在记录树被 statelsss 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 队列将带有 ID 的信号发送到处理器 bean,而不是调用 asyc ejb(和消息驱动的 bean 从数据库读取数据),但我想尽可能避免这种情况。
另一种解决方案是将整个记录树作为分离的 JPA 对象传递给处理器异步 EJB,而不是从数据库中读回数据。
我能否以某种方式使异步 EJB 在此结构中正常工作?
--更新--
我正在考虑使用 Weblogic JMS。这里还有一个问题。在大负载的情况下,当队列中有 100 000 个或更多数据(这将是正常的)并且没有互联网连接时,队列中的所有数据都将失败。如果在通过 Internet 发送数据(通过 doSomethingForLongWithData
方法)期间出现该异常(或任何异常),数据将根据 Weblogic 的 redelivery-limit
和 repetitaion
设置回滚到原始队列.此回滚事件将在托管服务器中的 Weblogic 上生成 100 000 个或更多线程来管理重新交付。新的大量后台进程可以杀死或至少减慢服务器速度。
我也可以使用 IBM MQ,因为我们有 MQ 基础设施。 MQ对Weblogic服务器没有这种影响,但是MQ没有redelivery-limit和delay功能。因此,如果出现错误(回滚),消息将立即再次出现在 MQ 上,没有延迟,我构建了一个手磨机。 Thread.sleep()
在 catch
条件下我猜想在 EE 应用程序中不是解决方案...
Is seems that the asynchronous bean tries to read the record tree before it was commited or inserted (JPA) by the statelsss EJB so record tree is not visible by async bean.
这是 bean 管理事务的预期行为。您正在从具有自己的事务上下文的 EJB 启动异步 EJB。异步 EJB 从不使用调用者事务上下文(参见 EJB 规范 4.5.3)。 只要您没有在持久性中使用事务隔离级别 "read uncommited",您就不会看到调用者仍未提交的数据。
你必须考虑这种情况,当异步作业不会提交时(例如应用程序服务器关闭或异常中止)。以下计算和更新是否重要?异步过程执行不成功或者连调用都没有调用是否可以恢复?
您可以考虑使用 bean 管理的事务,在调用异步 EJB 之前提交。或者,您可以将数据更新委托给具有新事务处理上下文的另一个 EJB。这将在调用异步 EJB 之前提交。这通常适用于不重要的东西,丢失或失败。
使用持久性和事务性 JMS 消息以及死信队列具有可靠处理计算和更新的优势,即使在中间停止/启动应用程序服务器或在处理期间出现临时错误也是如此。
您只需要在带有事务标记的方法旁边调用异步方法,以便在提交事务时调用。
例如,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;
}