简体   繁体   English

JMS和Java EE事务

[英]JMS and Java EE transactions

If you have a some java code (kicked off by JMS message delivery) running inside an EJB container and that code puts another JMS message into the same queue, how do you prevent that message from being delivered until the code that kicked it off is complete and its transaction is committed? 如果您在EJB容器中运行了一些Java代码(由JMS消息传递启动),并且该代码将另一个JMS消息放入同一队列中,那么如何阻止该消息传递,直到将其踢掉的代码完成为止和它的交易已提交? Basically, I'm experiencing a transaction concurrency issue. 基本上,我遇到交易并发问题。 I've got code (in EJB) that gets kicked off by JMS message A. This code does some stuff, then it does a database insert (which wont commit until all of this code is done executing because of container managed EJB transactions). 我有JMS消息A所启动的代码(在EJB中)。该代码完成了一些工作,然后进行了数据库插入(由于容器管理的EJB事务,直到所有这些代码执行完毕,它才提交)。 Then it puts a message (message B) that has the id of the DB row that was just inserted into the queue. 然后,它放入一条消息(消息B),该消息具有刚插入队列中的数据库行的ID。 Then it does some other stuff in the same transaction that takes a little while. 然后,它会在同一事务中完成一些其他工作,而这需要花费一些时间。

Well, shortly after this message with the ID of the database row is put into the queue, it gets delivered and kicks off code that tries to query that row that got inserted by code that got kicked off by message A. The trouble is, that code that inserted that row is still executing and its transaction hasn't committed yet. 好吧,将带有数据库行ID的消息放入队列后不久,它就被传递并启动了代码,该代码试图查询由消息A所启动的代码插入的行。麻烦是,那插入该行的代码仍在执行,并且其事务尚未提交。 So the database row in question isn't in the DB to be queried. 因此,有问题的数据库行不在要查询的数据库中。 The result is that code that is kicked off by message B errors out because it can't find the DB row it needs. 结果是由于消息B错误而启动的代码无法找到所需的数据库行。

How do I prevent this? 我该如何预防? I've done hours of research on JMS and transactions in Java EE container. 我已经完成了有关Java EE容器中的JMS和事务的数小时研究。 This one tutorial I've read is saying that you can't receive a message and send a reply in the same transaction. 我读过的一篇教程说,您无法在同一笔交易中收到消息并发送回复。 So shouldn't the container not commit the message to the queue until all of the transaction is complete? 因此,在所有事务完成之前,容器是否不应该将消息提交到队列中?

Sorry if this question is garbled. 抱歉,这个问题很乱。 I'm trying to explain the best I can. 我正在尽力解释。 There's way too much code to be pasted in here. 这里粘贴的代码太多了。 But the environment is WildFly 8.1, the executable code is inside stateless EJBs, JPA is used for database access, and the messages are in queues, not topics. 但是环境是WildFly 8.1,可执行代码在无状态EJB内,JPA用于数据库访问,消息在队列中,而不是主题中。 I hope that's enough info. 我希望有足够的信息。

// 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

I had to change regular connection factory: 我不得不更改常规连接工厂:

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

To XA connection factory: 到XA连接工厂:

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

This made things stop working at first, because I was initializing the connection only once per EJB in an @PostConstruct and closing it in @PreDestroy annotated methods. 这使事情一开始就停止了,因为我只在@PostConstruct中为每个EJB初始化一次连接,并在带注释的@PreDestroy方法中将其关闭。 So in addition to that, I had to move connection and session generation to the beginning of each method and close them at the end of each method. 因此,除此之外,我还必须将连接和会话生成移到每个方法的开头,并在每个方法的末尾将其关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM