Question

En utilisant Spring-JMS, il est possible de recevoir des messages dans un contexte de transaction externe via le DefaultMessageListenerConainer.

Cependant le seul moyen documenté de écrivez Un message est via JmsTemplate.send(…) Et je ne vois pas comment cela peut être contraint d'utiliser une donnée TransactionManager.

Est-ce que quelqu'un peut-il me montrer la bonne direction?


Plus d'informations: s'assurer qu'un gestionnaire de transactions est disponible (WebSphereUowTransactionManager), utilisant JmsTemplate.write contre un oracle AQjmsFactory.getQueueConnectionFactory(dataSource) résulte en:

org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
  at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
  at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
  at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:469)
  at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:534)
Caused by: oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
  at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1053)
  at oracle.jms.AQjmsSession.commit(AQjmsSession.java:1021)
  at org.springframework.jms.support.JmsUtils.commitIfNecessary(JmsUtils.java:217)
  at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:573)
  at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:536)
  at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:466)
  ... 24 more
Caused by: java.sql.SQLException: could not use local transaction commit in a global transaction
  at oracle.jdbc.driver.PhysicalConnection.disallowGlobalTxnMode(PhysicalConnection.java:6647)
  at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3635)
  at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3680)
  at oracle.jdbc.OracleConnectionWrapper.commit(OracleConnectionWrapper.java:133)
  at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1049)
  ... 29 more

Donc, même si je n'ai aucune raison de douter des conseils ci-dessous, je ne suis pas en mesure de le tester car je ne peux pas comprendre comment faire en sorte que AQ JMS ne tente pas de validation. Mettra à jour en apprenant plus.

Était-ce utile?

La solution

Ma compréhension est que les producteurs JMS sont intrinsèquement TRANSÉ VIRE JTA. En envoyant un message via JMS MessageProducer, la transaction JTA à thread-local est utilisée (si une est présente).

Cela fait allusion par le manuel du printemps (Section 21.2.5):

JmsTemplate peut également être utilisé avec le JtaTransactionManager et un JMS compatible XA ConnectionFactory pour effectuer des transactions distribuées. Notez que cela nécessite l'utilisation d'un gestionnaire de transactions JTA ainsi qu'un ConnectionFactory.

Ceci est également suggéré par JmsAccessor.setSessionTransacted (La superclasse de JmsTemplate) (javadoc):

Définissez le mode de transaction utilisé lors de la création d'une session JMS. La valeur par défaut est "faux". Notez que dans une transaction JTA, les paramètres passaient à create(Queue/Topic)Session(boolean transacted, int acknowledgeMode) La méthode n'est pas prise en compte. Selon le contexte de la transaction J2EE, le conteneur prend ses propres décisions sur ces valeurs. De manière analogue, ces paramètres ne sont pas pris en compte dans une transaction gérée localement, car l'accessoire fonctionne sur une session JMS existante dans ce cas.

La définition de ce drapeau sur "True" utilisera une courte transaction JMS locale lors de l'exécution d'une transaction gérée, et une transaction JMS locale synchronisée en cas de transaction gérée (autre qu'une transaction XA) est présente. Ce dernier a l'effet d'une transaction JMS locale gérée parallèlement à la transaction principale (qui pourrait être une transaction JDBC native), la transaction JMS commettant juste après la transaction principale.

Donc, en démarrant une transaction JTA (c'est-à-dire en utilisant l'API de transaction de Spring avec JtaTransactionManager) et appeler JmsTemplate.send(...), vous enverrez le message lié à cette transaction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top