使用ChainedTransactionManager(JDBC+;JPA)时,不支持传播会在JDBC中创建失败的事务
我正在开发一个使用JDBC(DAO的扩展名参数JDBCDAOSupport)的现有Spring应用程序。配置了四个数据源,每个数据源都有自己的DataSourceTransactionManager。(尽管由于某种原因,只有一个注册了tx:annotation-driven) 我最近在应用程序中添加了JPA(SpringDataJPA),并配置了两个EntityManagerFactory(目前我不需要另外两个数据源)。我还为这些数据源配置了两个JPATransactionManager并删除了相应的DataSourceTransactionManager,因为JPATransactionManager也可以用于JDBC事务。(如果我错了,请纠正我) 似乎我需要能够拥有分布式事务,因为两个数据源(到两个不同的数据库)需要在一个服务方法中访问(通过JPA)。由于我没有设置JTA(其中一个数据库缺少XA驱动程序)所需的全部资源,我决定尝试一下Spring ChainedTransactionManager。遗憾的是,这并没有如预期的那样成功。如果我只调用一个只使用JPA的服务方法,那么一切都很好。 虽然当我调用一个使用JDBC查找的现有服务方法时,该方法的类级别@transactional注释的传播设置为NOT_SUPPORTED,然后使用JPA调用和@transactional调用另一个服务方法,但我得到一个异常:使用ChainedTransactionManager(JDBC+;JPA)时,不支持传播会在JDBC中创建失败的事务,jpa,jdbc,spring-data,transactional,Jpa,Jdbc,Spring Data,Transactional,我正在开发一个使用JDBC(DAO的扩展名参数JDBCDAOSupport)的现有Spring应用程序。配置了四个数据源,每个数据源都有自己的DataSourceTransactionManager。(尽管由于某种原因,只有一个注册了tx:annotation-driven) 我最近在应用程序中添加了JPA(SpringDataJPA),并配置了两个EntityManagerFactory(目前我不需要另外两个数据源)。我还为这些数据源配置了两个JPATransactionManager并删除了
Caused by: java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@462cf9d9] for key [org.jboss.jca.adapters.jdbc.WrapperDataSource@3fbb4c32] bound to thread [http-/127.0.0.1:8080-5]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:189) [spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:403) [spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
经过一些调试,我发现Spring中的事务被添加到“TransactionSynchronizationManager.bindResource”方法中ThreadLocal上的映射中。问题是,当使用不支持@transactional和propogation的JDBC调用时,无论如何都会进行事务并通过该方法注册。当JpaTransactionManager尝试绑定其资源时,它已经在映射上(未标记为void),这会导致错误发生
将封装JDBC调用的服务调用的传播更改为默认的“REQUIRED”,可以解决此问题。
我不知道为什么Spring在不支持事务注释的情况下仍在创建该事务。如果它创建了该事务,则不应绕过JpaTransactionManager。
所以我想知道的是,当Spring在NamedParameterJdbcDaoSupport中创建事务时,是否有某种方法可以告诉它也使用JpaTransactionManager。(实际上JdbcDaoSupport…实际上是DataSourceUtils)
我们使用的是Spring3.2.5、SpringDataJPA1.6.0,我使用的是Hibernate4.2.0作为JpaVendor
如果没有ChainedTransactionManager,则不会出现此问题
数据源:
<bean id="dataSourceCompta" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/comptaDS"/>
</bean>
<bean id="dataSourceUnisys" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/insoverDS"/>
</bean>
<bean id="dataSourceInsoverwebMysql" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/insoverWebDS"/>
</bean>
<bean id="dataSourceBatch" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/batchDS"/>
</bean>
剩余的单个JDBC事务管理器(无JPA对应项):
JPA事务管理器:
<bean id="jpaUnisysTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryUnisys"/>
<qualifier value="unisys" />
</bean>
<bean id="jpaMysqlTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryMysql"/>
<qualifier value="mysql" />
</bean>
我的ChainedTransactionManager:
<bean id="chainedTransactionManager" class="org.springframework.data.transaction.ChainedTransactionManager">
<constructor-arg>
<list>
<ref bean="jpaUnisysTransactionManager" />
<ref bean="jpaMysqlTransactionManager" />
</list>
</constructor-arg>
</bean>
JPA实体管理器工厂:
<bean name="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactoryUnisys" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/some-persistence.xml"/>
<property name="dataSource" ref="dataSourceUnisys"/>
<property name="persistenceUnitName" value="unisysPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<!-- properties -->
</property>
</bean>
<bean id="entityManagerFactoryMysql" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/some-persistence.xml"/>
<property name="dataSource" ref="dataSourceCompta"/>
<property name="persistenceUnitName" value="mysqlPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<!-- properties -->
</property>
</bean>
现在我已经“修复”了这个问题,将所有类级别的事务注释更改为具有propagation.REQUIRED(默认)而不是NOT_SUPPORTED。虽然我真的不喜欢这种解决方案,因为可能有人有充分的理由将这些传播设置为不受支持。我也尝试过支持,但使用它与不支持有相同的问题:当名为ParameterJDBCDAOSupport的DAO执行查询时,Spring DataSourceUtils仍在进行事务。
当服务上没有设置事务性注释时,所有注释都可以正常工作
<bean name="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactoryUnisys" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/some-persistence.xml"/>
<property name="dataSource" ref="dataSourceUnisys"/>
<property name="persistenceUnitName" value="unisysPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<!-- properties -->
</property>
</bean>
<bean id="entityManagerFactoryMysql" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/some-persistence.xml"/>
<property name="dataSource" ref="dataSourceCompta"/>
<property name="persistenceUnitName" value="mysqlPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<!-- properties -->
</property>
</bean>