CMT MDB的默认回滚行为是将邮件返回到目标,以便再次处理。
即使事务被回滚,是否可以避免重新传递托管MDB处理的消息? (或者可以配置容器处理的确认行为)。
到目前为止,我想出了以下替代方案:
TransactionAttributeType.REQUIRES_NEW
,但它会创建业务方案
事件可以被处理两次,因为消息可能是
商业交易成功后不予承认。阅读this tutorial后,我仍然不确定如何解决这个问题,但到目前为止,使用专有WebLogic Console控制邮件传递失败似乎是正确的选择。在这种情况下,为队列上的重新传递设置限制 - 例如:3次尝试。它会产生处理开销,因为无效的业务事件可能会失败3次,但我可以保证系统的完整性。
你们有什么想法?
我有一个与业务事务集成的MDB,它使用JPA(WebLogic 10.3.6中的EclipseLink)。一切都在运行CMT并且事务是分发的。事务和消息确认由容器控制。
如果JPA提供程序中发生异常(例如:非空列的null值),则正在重新传递消息,因为提供程序正在回滚事务并且消息未得到确认。如果我捕获异常并不重要,EclipseLink无论如何都会回滚事务。我知道这是JPA的正确行为。
此外,使用MessageDrivenContext.getRollbackOnly()
会返回 false 。我希望它是真的。
如果我使用TransactionAttributeType.REQUIRES_NEW
执行我的业务方法,则回滚事务并且不重新传递消息但是消息处理事务将是独立的,这也是不希望的。我确实建立了一个JDBC存储来将消息保存在数据库中。
我会留下一些虚拟课来说明我的观点。
MDB消息处理
在提取有效负载后,我将其转发到会话bean以处理持久性逻辑。
public void onMessage(Message message) {
try {
// Extract the payload
TextMessage txtMsg = (TextMessage) message;
String employeeName = txtMsg.getText();
// Call service
service.createEmployee(employeeName);
} catch (Exception e) {
e.printStackTrace();
} finally {
// When the JPA provider rollbacks back the transaction, this value
// is still "false"
log.info(String.format("Rollback only: [%s]", mdContext.getRollbackOnly()));
}
}
强制向JPA提供程序发送例外
将null
留在非空字段中来强制执行错误。
// Message and business will run in the same transaction
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void createEmployee(String name) {
Employee employee = new Employee();
employee.setName(null); // Null value to force constraint error
try {
// This part triggers the exception within the JPA provider, and the
// Java EE transaction is rolledback and forces the JMS message to be
// redelivered.
em.persist(employee);
} catch (Exception e) {
// Capturing the exception does not affect the rollback behavior
e.printStackTrace();
}
}
这是EclipseLink抛出的错误。它包含在RuntimeException
中,因此它是一个系统异常,事务将回滚。
javax.ejb.EJBTransactionRolledbackException: EJB Exception: ; nested exception is: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.1.v20111018-r10243): org.eclipse.persistence.exceptions.DatabaseException
答案 0 :(得分:2)
拥有2 tx的恕我直言,正是您所寻找的。
有一个事务处理由EJB容器启动的MDB,然后在MDB中,您在使用Transaction.REQUIRES_NEW注释的无状态会话Bean(SLSB)中调用业务方法,因此您的业务逻辑处理数据库在其自己的孤立事务中被隔离。
当您从SLSB的方法返回时,无论您的业务逻辑方法发生什么,MDB tx将由MDB的onMessage()方法结束时的容器提交,并且消息将被消耗/从Q中移除。重新处理的可能性为零......
唯一的例外是如果MDB本身出现问题,但您可以轻松处理它
干杯
答案 1 :(得分:0)
您使用的是哪个Q提供商?
似乎你已经涵盖了可能性
恕我直言最好的解决方案是在单独的外观SLSB中使用JPA隔离您的业务逻辑,并使用“事务新”属性并仍然使用CMT语义,因此如果此SLSB中发生了错误,您仍然可以提交tx其中onMessage tx由Application Server自动启动
这听起来类似于你的第一个解决方案。
对我来说,第二个选择是配置Q管理器,这样当消息在Q上“重新传送”一定次数(即由于tx回滚而返回Q)时,消息被移动到另一个Q(死信队列()并在此Q ...上配置一些监控/警报系统
Denis(JMSToolBox的作者)