在我的 Java EE 应用程序中,我实现了一个异步数据库记录器作为 MDB,它通过 JMS 接收 XML 消息并将它们写入数据库。
在另一个 MDB 中,我创建一条日志消息,并使用以下代码将它们发送到记录器 MDB 的输入队列:
public static void log(String correlId, String message, String data) throws Exception{
SysLogEntry sysLogEntry = new SysLogEntry();
sysLogEntry.setCorrelId(correlId);
sysLogEntry.setDatetimeCreate(new Date());
sysLogEntry.setMessage(message);
sysLogEntry.setData(data);
ConnectionFactory jmsConnectionFactory = (ConnectionFactory)initialContext.lookup(JMS_CONNECTION_FACTORY_JNDI_NAME);
Destination logEventDestination = (Destination) initialContext.lookup(LOG_EVENT_DESTINATION_JNDI_NAME);
JmsUtils.sendMsgToDestination(JaxbUtils.toString(sysLogEntry, jaxbContext), jmsConnectionFactory, logEventDestination, false, Session.AUTO_ACKNOWLEDGE);
}
public static void sendMsgToDestination(String payload, ConnectionFactory connFactory, Destination destination, boolean sessionTransacted, int acknowledgeMode) throws JMSException{
if(payload == null)
throw new IllegalArgumentException("Message payload is null");
if(connFactory == null)
throw new IllegalArgumentException("Connection factory is null");
if(destination == null)
throw new IllegalArgumentException("Message destination is null");
Connection connection = null;
try{
connection = connFactory.createConnection();
Session session = connection.createSession(sessionTransacted, acknowledgeMode);
MessageProducer messageProducer = session.createProducer(destination);
TextMessage textMessage = session.createTextMessage();
textMessage.setText(payload);
messageProducer.send(textMessage);
} finally {
if(connection != null){
try{
connection.close();
} catch (JMSException ignore){
}
}
}
}
哪里
SysLogEntry
是一个带有 JAXB 注释的类,我用它来进行序列化JMS_CONNECTION_FACTORY_JNDI_NAME
是 XA 连接工厂的 JNDI 名称
但是,每次回滚创建日志消息的事务时,日志消息都不会放入记录器输入队列中。
有人可以告诉我我的代码有什么问题吗?我考虑过使用一个单独的无状态 session bean,它将启动一个新事务来生成日志消息,但这种方法有一个缺点:在 EJB 内,我可以轻松地让容器注入(inject)记录器 bean,但我也有非 EJB我想在其中进行异步日志记录的对象。
我的应用程序服务器是Weblogic 10.3.3
最佳答案
如果出现系统异常(或sessionContext.setRollbackOnly
),全局事务将由容器回滚(如果您使用容器管理的事务)。
这意味着对全局事务中列出的 XA 感知资源的任何操作都会回滚。
在您的情况下,这包括您想要发送到记录器的待处理消息。这一项被删除,因为事务已回滚。
就您的情况而言,如果您使用非 XA 连接工厂,那么这应该足够了。这样消息应该立即发送(如果有记录器甚至有帮助)。因此,发送在仅跨越 JMS 发送任务的本地事务中运行。
对于非 EJB 对象:您可以使用非 XA 连接工厂将发送功能提取到普通 Java 类(= 不是 EJB)中,并从 EJB 和普通类中使用它。
关于logging - 使用 EJB 3 发送 JMS 消息时的事务划分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18571387/