Spring 3.1 + JPA 2 (via Hibernate 4) + MQ = Transaktionsproblem?

gorefest

Erfahrenes Mitglied
Hi,

wir haben hier aktuell Schwierigkeiten mit der o.a. Konfig. Wir haben die Anwendung auf JPA umgestellt, aber überall, wo MQ zum Einsatz kommt kracht es :

Code:
: Cannot deactivate transaction synchronization - not active
at org.springframework.transaction.support.TransactionSynchronizationManager.clearSynchronization(TransactionSynchronizationManager.java:329)

at org.springframework.transaction.support.TransactionSynchronizationManager.clear(TransactionSynchronizationManager.java:464)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1005)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:804)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)

at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)

at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)

at de.axa.opmpastmodulectvupdate.impl.CtvUpdateReceiveImpl$$EnhancerByCGLIB$$b7a04acc.run(<generated>)

Unsere Bean/MQ Konfig sieht so aus :

Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="
    	http://www.springframework.org/schema/beans 
    	http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    	http://www.springframework.org/schema/context 
    	http://www.springframework.org/schema/context/spring-context-3.1.xsd 
    	http://www.springframework.org/schema/util 
    	http://www.springframework.org/schema/util/spring-util-3.1.xsd 
    	http://www.springframework.org/schema/tx 
    	http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
    	http://www.springframework.org/schema/aop 
    	http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

	<context:component-scan base-package="de.foobatz.prstmodulectvupdate" />
		

	<bean id="scheduledTimerCtvUpdateTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
		<property name="delay" value="60000" />
		<property name="period" value="60000" />
		<property name="timerTask" ref="ctvUpdateTimer" />
	</bean>

	<bean id="scheduledTimerReceiveTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
		<property name="delay" value="60000" />
		<property name="period" value="60000" />
		<property name="timerTask" ref="ctvUpdateReceiveTimer" />
	</bean>

	<bean id="ctvUpdateTimer" class="de.foobatz.prst.business.timer.GenericTimer">
	    <property name="batchModule" ref="ctvUpdateTask"/> 
	</bean>

	<bean id="ctvUpdateReceiveTimer" class="de.foobatz.prst.business.timer.GenericTimer">
		<!-- TODO: transactionManager -->
		<property name="batchModule" ref="ctvUpdateReceiveTask"/>
	</bean>


	<!-- 1. Standard-Batch-MQs KOMO.TV.ARCHIV6.P2H/.H2P für CTVUpdate (Job TV51F) -->
	<bean id="ctvupdateReqQueueJmsTemplateBatch1" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactoryCtvupdate" />
		<property name="defaultDestination" ref="ctvupdateReqQueueBatch1" />
	</bean>
	<bean id="ctvupdateReqQueueBatch1" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate" />
		<property name="jndiName" value="${jndi.queue.ctvupdate.batch.tv51f.req}" />
	</bean>

	<bean id="ctvupdateReplyQueueJmsTemplateBatch1" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactoryCtvupdate" />
		<property name="defaultDestination" ref="ctvupdateReplyQueueBatch1" />
		<property name="sessionAcknowledgeMode" value="#{T(javax.jms.Session).CLIENT_ACKNOWLEDGE}" />
		<property name="receiveTimeout"
			value="#{T(org.springframework.jms.core.JmsTemplate).RECEIVE_TIMEOUT_NO_WAIT}" />
		<!-- entspricht in Java: jmsTemplateResp.setReceiveTimeout(JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); 
			siehe "Spring Expression Language" (SpEL) -->
	</bean>
	<bean id="ctvupdateReplyQueueBatch1" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate" />
		<property name="jndiName" value="${jndi.queue.ctvupdate.batch.tv51f.reply}" />
	</bean>


	<!-- Erst nach Abloesung von ArcMat: -->
	<!-- 2. Batch-MQs KOMO.TV.ARCHIV.P2H/.H2P für CTVUpdate inkl. VGMUpdate 
		und "alte" Datenstruktur ohne JobId (Job TV51A) -->
	<bean id="ctvupdateReqQueueJmsTemplateBatchMitVGM" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactoryCtvupdate" />
		<property name="defaultDestination" ref="ctvupdateReqQueueBatchMitVGM" />
	</bean>
	<bean id="ctvupdateReqQueueBatchMitVGM" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate" />
		<property name="jndiName" value="${jndi.queue.ctvupdate.batch.tv51a.req}" />
	</bean>

	<bean id="ctvupdateReplyQueueJmsTemplateBatchMitVGM" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactoryCtvupdate" />
		<property name="defaultDestination" ref="ctvupdateReplyQueueOnlineMitVGM" />
		<property name="sessionAcknowledgeMode" value="#{T(javax.jms.Session).CLIENT_ACKNOWLEDGE}" />
		<property name="receiveTimeout"
			value="#{T(org.springframework.jms.core.JmsTemplate).RECEIVE_TIMEOUT_NO_WAIT}" />
		<!-- entspricht in Java: jmsTemplateResp.setReceiveTimeout(JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); 
			siehe "Spring Expression Language" (SpEL) -->
	</bean>
	<bean id="ctvupdateReplyQueueBatchMitVGM" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate" />
		<property name="jndiName" value="${jndi.queue.ctvupdate.batch.tv51a.reply}" />
	</bean>


	<!-- 3. Online-MQs KOMO.TV.ARCHIV2.P2H/.H2P für CTVUpdate inkl. VGMUpdate 
		und "alte" Datenstruktur ohne JobId (Job TV51B) -->
	<bean id="ctvupdateReqQueueJmsTemplateOnlineMitVGM" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactoryCtvupdate" />
		<property name="defaultDestination" ref="ctvupdateReqQueueOnlineMitVGM" />
	</bean>
	<bean id="ctvupdateReqQueueOnlineMitVGM" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate" />
		<property name="jndiName" value="${jndi.queue.ctvupdate.online.tv51b.req}" />
	</bean>

	<bean id="ctvupdateReplyQueueJmsTemplateOnlineMitVGM" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactoryCtvupdate" />
		<property name="defaultDestination" ref="ctvupdateReplyQueueOnlineMitVGM" />
		<property name="sessionAcknowledgeMode" value="#{T(javax.jms.Session).CLIENT_ACKNOWLEDGE}" />
		<property name="receiveTimeout"
			value="#{T(org.springframework.jms.core.JmsTemplate).RECEIVE_TIMEOUT_NO_WAIT}" />
		<!-- entspricht in Java: jmsTemplateResp.setReceiveTimeout(JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); 
			siehe "Spring Expression Language" (SpEL) -->
	</bean>
	<bean id="ctvupdateReplyQueueOnlineMitVGM" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate" />
		<property name="jndiName" value="${jndi.queue.ctvupdate.online.tv51b.reply}" />
	</bean>


	<!-- Factory zur Herstellung der Verbindung -->
	<bean id="connectionFactoryCtvupdate" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="${jndi.channel.ctvupdate.url}" />
		<property name="jndiTemplate" ref="jndiTemplate" />
	</bean>

	<bean id="jmsTransactionManagerCtv"
		class="org.springframework.jms.connection.JmsTransactionManager">
		<property name="connectionFactory">
			<ref local="connectionFactoryCtvupdate" />
		</property>
	</bean>


</beans>

Unsere JPA Config hingegen so :

Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="
    	http://www.springframework.org/schema/beans 
    	http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    	http://www.springframework.org/schema/context 
    	http://www.springframework.org/schema/context/spring-context-3.1.xsd 
    	http://www.springframework.org/schema/util 
    	http://www.springframework.org/schema/util/spring-util-3.1.xsd 
    	http://www.springframework.org/schema/tx 
    	http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
    	http://www.springframework.org/schema/aop 
    	http://www.springframework.org/schema/aop/spring-aop-3.1.xsd" >
		
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" 
		p:showSql="true"
		p:generateDdl="true"
		p:databasePlatform="de.foobatz.prstmoduledb.dialect.DB2390DialectCustom"/>
		
	<util:properties id="jpaProperties">
		<prop key="hibernate.jdbc.fetch_size">100</prop>
<!-- 		<prop key="hibernate.search.default.indexBase">${hibernate.search.index}</prop> -->
		<prop key="hibernate.search.default.exclusive_index_use">false</prop>
		<prop key="hibernate.search.default.locking_strategy">native</prop>
		<prop key="hibernate.search.lucene_version">LUCENE_CURRENT</prop>
		<prop key="hibernate.hbm2ddl.auto">validate</prop>
		<prop key="hibernate.cache.provider_class">org.hibernate.cache.SingletonEhCacheProvider</prop>
  		<prop key="hibernate.cache.provider_configuration">/ehcache.xml</prop>
  		<prop key="hibernate.cache.use_second_level_cache">true</prop>
  		<prop key="hibernate.cache.use_query_cache">true</prop>
  		<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
	</util:properties>				
		
	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
		p:dataSource-ref="dataSource" 
		p:packagesToScan="de.foobatz.prstmoduledb.vo" 		
		p:jpaVendorAdapter-ref="jpaVendorAdapter"
		p:jpaProperties-ref="jpaProperties"/>  

	<bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager"
		p:entityManagerFactory-ref="entityManagerFactory" 
		p:dataSource-ref="dataSource" />	

	<bean id="dataSource" 
		class="com.mchange.v2.c3p0.ComboPooledDataSource" 
		destroy-method="close"
		p:driverClass="${jdbc.db2.driverClassName}"
		p:idleConnectionTestPeriod="60"
		p:jdbcUrl="${jdbc.url.prst}"
		p:user="${jdbc.username.prst}" 
		p:password="${jdbc.password.prst}" 
		p:minPoolSize="0" 
		p:maxPoolSize="20" />

    <bean id="commLogServerThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" 
    	p:corePoolSize="2" 
    	p:maxPoolSize="5" 
    	p:threadNamePrefix="CommLogServerThread-"/>

    <aop:aspectj-autoproxy/>
    <context:component-scan base-package="de.foobatz.prstmoduledb" />
    <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>    
</beans>

Ich glaube, dass da irgendwie ein Transaction Manager konfiguriert werden muss.

Hat einer von Euch eine Idee?

Danke im Voraus!
Grüße,
gore
 
Zuletzt bearbeitet:
Hallo,

von deiner Konfiguration und Fehlermeldung her zu Urteilen... schau mal hier:
http://static.springsource.org/spri...ork/jms/connection/JmsTransactionManager.html

Bzw. hier:
https://jira.springsource.org/browse/SPR-7306

setTransactionSynchronization

public final void setTransactionSynchronization(int transactionSynchronization)
Set when this transaction manager should activate the thread-bound transaction synchronization support. Default is "always".
Note that transaction synchronization isn't supported for multiple concurrent transactions by different transaction managers. Only one transaction manager is allowed to activate it at any time.

See Also:
SYNCHRONIZATION_ALWAYS, SYNCHRONIZATION_ON_ACTUAL_TRANSACTION, SYNCHRONIZATION_NEVER, TransactionSynchronizationManager, TransactionSynchronization

Musst du hier vielleicht "einfach" auf SYNCHRONIZATION_ON_ACTUAL_TRANSACTION stellen?

Gruß Tom
 
Hi und danke für die Antwort!

Das hat auf jeden Fall schon mal geholfen; allerdings haben wir nun hin- und wieder leere Queue-Nachrichten, d.h. es ist eine Message in der Queue, aber diese hat keinen Inhalt.

Kann das sein, dass die beiden Systeme (JPA + MQ) in einen TX-Container müssen? Oder macht Spring das für uns?

Danke schon mal im voraus,
gore
 
OK, wir sind nun einen Schritt weiter, der mir aber einiges an Fragen aufwirft.

Die Queue bekommt einen Eintrag und macht keinen Commit.

Die Konfig ist nun wie folgt verändert (Danke übrigens an Thomas, der erste Schritt war tatsächlich die Synchronisierung!):

Code:
	<!-- Beim Senden in die Request-Queue soll direkt commited werden, deshalb 
		braucht die Request-Queue hier entsprechende Attribute -->
	<bean id="masterindexJmsOperations"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager">
			<ref local="masterindexjmsTransactionManager" />
		</property>
		<property name="target">
			<ref local="masterindexReqQueueJmsTemplate" />
		</property>
		<property name="transactionAttributeSource">
		  <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
		</property>		
	</bean>


Code:
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void serviceAufruf(final WriteArchiveEntriesRequest request)

Wenn nur @TransactionAttribute verwendet wird, findet kein Commit statt, wenn @Transactional verwendet wird, jedoch wohl.

In der Spring Doku steht, dass beide beachtet werden(!?). Evtl. ist AnnotationTransactionAttributeSource nicht die richtige Wahl?

Danke+Grüße,
gore
 
Zurück