如果您有一些java代码(由JMS消息传递启动)在EJB容器中运行,并且该代码将另一个JMS消息放入同一队列中,那么在启动它的代码完成并提交其事务之前,如何防止该消息被传递?基本上,我遇到了事务并发问题。我有由JMS消息A启动的代码(在EJB中)。这段代码做了一些事情,然后它做了一次数据库插入(由于容器管理的EJB事务,在执行完所有这些代码之前,它不会提交)。然后,它放入一条消息(消息B),该消息具有刚刚插入到队列中的DB行的id。然后,它在同一事务中做一些其他的事情,这需要一段时间。
在将带有数据库行ID的消息放入队列后不久,它就会被传递,并启动代码,尝试查询由消息A启动的代码插入的行。问题是,插入该行的代码仍在执行,其事务尚未提交。因此,有问题的数据库行不在要查询的数据库中。结果是由消息B启动的代码出现错误,因为它找不到所需的DB行。
我如何防止这种情况发生?我对Java EE容器中的JMS和事务做了几个小时的研究。我读过的这篇教程是说,你不能在同一事务中既接收消息又发送回复。那么,在所有事务完成之前,容器不应该将消息提交到队列吗?
如果这个问题乱码了,很抱歉。我在尽我所能地解释。这里要粘贴的代码太多了。但是环境是JPA8.1,可执行代码在无状态的WildFly中,数据库访问使用JPA8.1,消息在队列中,而不是主题中。我希望这是足够的信息。
// 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发布于 2016-09-30 04:49:25
我不得不改变常规的连接工厂:
@Resource(mappedName = "java:/ConnectionFactory")
ConnectionFactory connectionFactory;到XA连接工厂:
@Resource(mappedName = "java:/JmsXA")
XAConnectionFactory connectionFactory;这使得事情一开始就停止了,因为我在@PostConstruct中对每个EJB只初始化一次连接,并在@PreDestroy注释的方法中关闭它。因此,除此之外,我必须将连接和会话生成移到每个方法的开头,并在每个方法的末尾关闭它们。
https://stackoverflow.com/questions/39627691
复制相似问题