Domanda

Usando Spring-JMS è possibile ricevere messaggi in un contesto di transazione esterna tramite il DefaultMessagelistenerContainer.

Tuttavia l'unico modo documentato per scrivere Un messaggio è via JmsTemplate.send(…) E non riesco a vedere come questo possa essere costretto a usare un dato TransactionManager.

Qualcuno può indicarmi nella giusta direzione?


Maggiori informazioni: garantire un gestore delle transazioni (WebSphereUowTransactionManager), usando JmsTemplate.write contro un oracolo AQjmsFactory.getQueueConnectionFactory(dataSource) Risultati in:

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

Quindi, mentre non ho motivo di dubitare del consiglio di seguito, non sono in grado di testarlo in quanto non riesco a capire come convincere AQ JMS a non tentare un commit. Aggiornerò mentre imparo di più.

È stato utile?

Soluzione

La mia comprensione è che i produttori di JMS lo sono intrinsecamente Transatto tramite JTA. Inviando un messaggio tramite JMS MessageProducer, viene utilizzata la transazione JTA-thread-locali (se è presente).

Questo è accennare dal manuale di primavera (Sezione 21.2.5):

JmsTemplate può anche essere usato con il JtaTransactionManager e un JMS con capacità XA ConnectionFactory Per eseguire transazioni distribuite. Si noti che ciò richiede l'uso di un gestore delle transazioni JTA e un correttamente configurato con XA ConnectionFactory.

Questo è anche suggerito da JmsAccessor.setSessionTransacted (la superclasse di JmsTemplate) (Javadoc):

Impostare la modalità di transazione utilizzata durante la creazione di una sessione JMS. L'impostazione predefinita è "falso". Si noti che all'interno di una transazione JTA, i parametri sono passati a create(Queue/Topic)Session(boolean transacted, int acknowledgeMode) Il metodo non è preso in considerazione. A seconda del contesto della transazione J2EE, il contenitore prende le proprie decisioni su questi valori. Analogamente, questi parametri non vengono presi in considerazione in una transazione gestita localmente, poiché l'accessore opera in una sessione JMS esistente in questo caso.

L'impostazione di questo flag su "TRUE" utilizzerà una breve transazione JMS locale quando si esegue fuori da una transazione gestita e una transazione JMS locale sincronizzata in caso di transazione gestita (diversa da una transazione XA). Quest'ultimo ha l'effetto di una transazione JMS locale gestita accanto alla transazione principale (che potrebbe essere una transazione JDBC nativa), con la transazione JMS che si impegna subito dopo la transazione principale.

Quindi, per iniziare una transazione JTA (cioè usando l'API di transazione di Spring con JtaTransactionManager) e chiamata JmsTemplate.send(...), invierai il messaggio associato a quella transazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top