gpt4 book ai didi

java - 在消息驱动 Bean (MDB) 中捕获异常

转载 作者:搜寻专家 更新时间:2023-11-01 01:45:01 25 4
gpt4 key购买 nike

我必须如何处理 mdb 中的异常?我有一种有趣的感觉,异常发生在 try catch block 之后,所以我无法捕获并记录它。 Glassfish v3 决定重复整个消息。它进入无限循环并在硬盘驱动器上写入大量日志文件。

我正在使用 Glassfishv3.01 + Eclipselink 2.0.1

public class SaveAdMessageDrivenBean implements MessageListener {

@PersistenceContext(unitName="QIS")
private EntityManager em;

@Resource
private MessageDrivenContext mdc;

public void onMessage(Message message) {
try {
if (message instanceof ObjectMessage) {
ObjectMessage obj = (ObjectMessage)message;
AnalyzerResult alyzres = (AnalyzerResult)obj.getObject();
save(alyzres);
}
} catch (Throwable e) {
mdc.setRollbackOnly();
log.log(Level.SEVERE, e);
}
}

@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void save(AnalyzerResult alyzres) throws PrdItemNotFoundException {

Some s = em.find(Some.class, somepk);
s.setSomeField("newvalue");

// SQL Exception happens after leaving this method because of missing field for ex.
}
}

最佳答案

你遇到了一个糟糕的消息中毒案例......

我看到的主要问题是:

  • 您在 onMessage() 中直接调用了 save() 方法:这意味着容器无法围绕 保存方法
  • 在任何情况下,save() 方法都应该有 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 以便在单独的事务中提交,否则它将加入 onMessage 事务(默认为 REQUIRED)并绕过您的异常处理代码,在成功执行 onMessage
  • 后提交

我要做的是:

save 方法移动到新的无状态 session bean:

@Stateless
public class AnalyzerResultSaver
{
@PersistenceContext(unitName="QIS")
private EntityManager em;

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void save(AnalyzerResult alyzres) throws PrdItemNotFoundException {
Some s = em.find(Some.class, somepk);
s.setSomeField("newvalue");
// SQL Exception happens after leaving this method
}
}

在您的 MDB 中注入(inject)这个 bean:

public class SaveAdMessageDrivenBean implements MessageListener {

@Inject
private AnalyzerResultSaver saver;

@Resource
private MessageDrivenContext mdc;

public void onMessage(Message message) {
try {
if (message instanceof ObjectMessage) {
ObjectMessage obj = (ObjectMessage)message;
AnalyzerResult alyzres = (AnalyzerResult)obj.getObject();
saver.save(alyzres);
}
} catch (Throwable e) {
mdc.setRollbackOnly();
log.log(Level.SEVERE, e);
}
}
}

另一个提示:在此代码中,消息中毒仍然存在。现在它派生自调用 mdc.setRollbackOnly(); 的行。

我建议在这里记录异常并将消息传输到毒队列,从而防止容器无限地重新提交消息。

更新:

“中毒队列”或“错误队列”只是一种保证您(希望可恢复)丢弃的消息不会完全丢失的方法。它大量用于无法保证消息数据正确性的集成场景。

设置毒队列意味着定义目标队列或主题并将“坏”消息重新传送到该目标。

运算符(operator)应定期检查此队列(通过专用应用程序)并修改消息并重新提交到“好”队列,或者丢弃消息并要求重新提交。

关于java - 在消息驱动 Bean (MDB) 中捕获异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13840023/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com