【问题标题】:JMS and Java EE transactionsJMS 和 Java EE 事务
【发布时间】:2017-01-30 08:40:32
【问题描述】:

如果您在 EJB 容器中运行了一些 java 代码(由 JMS 消息传递启动),并且该代码将另一条 JMS 消息放入同一个队列中,您如何防止该消息被传递,直到启动它的代码off 完成并且它的事务被提交?基本上,我遇到了事务并发问题。我有由 JMS 消息 A 启动的代码(在 EJB 中)。此代码执行一些操作,然后执行数据库插入(由于容器管理的 EJB 事务,在所有此代码执行完成之前不会提交)。然后它会放置一条消息(消息 B),该消息具有刚刚插入队列的 DB 行的 id。然后它在同一个事务中做一些其他的事情,这需要一点时间。

好吧,在这条带有数据库行 ID 的消息被放入队列后不久,它就会被传递并启动代码,该代码尝试查询由消息 A 启动的代码插入的行。麻烦的是也就是说,插入该行的代码仍在执行,其事务尚未提交。因此,有问题的数据库行不在要查询的数据库中。结果是由消息 B 启动的代码由于找不到所需的 DB 行而出错。

如何防止这种情况发生?我已经对 Java EE 容器中的 JMS 和事务进行了数小时的研究。我读过的这个教程是说你不能在同一个事务中接收消息并发送回复。那么容器不应该在所有事务完成之前不将消息提交到队列吗?

对不起,如果这个问题是乱码。我正在尽力解释。这里要粘贴的代码太多了。但是环境是 WildFly 8.1,可执行代码在无状态 EJB 中,JPA 用于数据库访问,消息在队列中,而不是主题中。我希望这是足够的信息。

// How factory and queues are declared in java code:

@Resource(mappedName = "java:/ConnectionFactory")
ConnectionFactory connectionFactory;

@Resource(mappedName = "java:jboss/exported/jms/queue/quequeA")
Queue queueA;

@Resource(mappedName = "java:jboss/exported/jms/queue/quequeB")
Queue queueB;

//Sending message:

TextMessage message = session.createTextMessage("some message goes here");
MessageProducer producer = session.createProducer(queueA); // samething for queueB
producer.send(message);

// how queues are configured in WidlFly's standalone.conf :

<jms-queue name="quequeA">
    <entry name="queue/quequeA"/>
    <entry name="java:jboss/exported/jms/queue/quequeA"/> <!-- same thing for queueB -->
</jms-queue>

<address-setting match="jms.queue.quequeA">
    <dead-letter-address>jms.queue.DLQ</dead-letter-address>
    <redelivery-delay>5000</redelivery-delay>
    <max-delivery-attempts>1</max-delivery-attempts>
    <max-size-bytes>10485760</max-size-bytes>
    <page-size-bytes>1048576</page-size-bytes>
    <address-full-policy>PAGE</address-full-policy>
    <message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>

// creating connection and session:
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // note: the application is running in the Java EE web/EJB environment, so both "fasle" and auto_acknowledge arguments shoudl be ignored according to the javadoc. I'm trying to use container-managed transactions for everything

【问题讨论】:

  • 说到消息,你确定你指的是 JMX 而不是 JMS 吗?
  • 对不起,JMS,你是对的。
  • @home - 该线程中描述的不是我所看到的。不仅消息没有回滚,而且消息被传递,并且由该消息触发的作业甚至在原始事务完成之前就开始执行。因此,无论原始事务是提交还是回滚,由消息触发的作业几乎总是失败,因为它试图在提交或回滚之前从数据库中获取行。
  • @Creature: 可能你的配置错误或者你发送的信息是“unmanaged”?

标签: transactions jms


【解决方案1】:

我不得不改变常规的连接工厂:

@Resource(mappedName = "java:/ConnectionFactory")
ConnectionFactory connectionFactory;

到 XA 连接工厂:

@Resource(mappedName = "java:/JmsXA")
XAConnectionFactory connectionFactory;

这使事情一开始就停止工作,因为我在 @PostConstruct 中的每个 EJB 中只初始化连接一次,并在 @PreDestroy 注释方法中关闭它。所以除此之外,我必须将连接和会话生成移到每个方法的开头,并在每个方法结束时关闭它们。

【讨论】:

  • 您好,我对此有一个澄清。是否强制要求为每条消息创建连接和会话?因为我觉得新连接和会话生成的延迟正在解决您的竞争状况。我尝试了这个 XA 连接工厂,每个 EJB 初始化连接一次,但我仍然面临同样的问题,因为消费者在数据保存在 DB 之前收到消息。
猜你喜欢
  • 2011-10-27
  • 2016-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-09
  • 2013-03-16
  • 2015-07-26
相关资源
最近更新 更多