Java Spring范围的代理事务可以通过JPA处理,但不能通过JDBC提交
我的情况是,我必须在一个应用程序中处理多个客户端,每个客户端都有单独的数据库。为了支持这一点,我使用了Spring自定义范围,这与内置的请求范围非常相似。用户在每个请求中进行身份验证,并可以基于传递的凭据设置上下文客户端ID。范围界定本身似乎工作正常 因此,我使用自定义作用域为数据源创建一个作用域代理,以支持每个客户机的不同数据库。我可以连接到适当的数据库 然后我为EntityManagerFactory创建了一个作用域代理以使用JPA。这部分看起来也不错 然后,我为PlatformTransactionManager添加了一个作用域代理,用于声明性事务管理。我在服务层上使用@Transactional,它很好地传播到SpringData支持的存储库层 只要我只使用JPA,一切都很好,工作正常。我甚至可以在我使用的请求中将上下文切换到不同的客户端,并且两个数据库的事务都得到了正确处理 当我尝试在一个自定义存储库中使用JDBCTempate时,问题就开始了。乍一看,一切看起来都很正常,因为没有抛出异常。但是,当我检查数据库中的对象时,我以为我是用基于JDBC的自定义存储库插入的,但它们不在那里 我确信我可以通过只声明JpaTransactionManager并将DataSource和EntityManagerFactory传递给它来同时使用JPA和JDBC——我检查了它,没有范围代理,它可以工作 所以问题是,当我对数据源、EntityManagerFactory和PlatformTransactionManager bean进行了范围代理时,如何使用JpaTransactionManager使JDBC与JPA协同工作?我提醒大家,仅使用JPA是完美的,但将普通JDBC添加到混合中是行不通的 更新1:还有一件事:所有只读SELECT操作在JDBC中也可以正常工作-仅写入INSERT、UPDATE、DELETE操作最终不会提交或回滚 更新2:正如@Tomasz建议的那样,我已经从EntityManagerFactory和PlatformTransactionManager中删除了作用域代理,因为它们确实是不需要的,并且比其他任何东西都更容易混淆 真正的问题似乎是在事务中切换范围上下文。TransactionSynchronizationManager在事务开始时将事务资源(即EMF或DS)绑定到线程。它能够展开作用域代理,因此它在启动事务时从活动的作用域绑定资源的实际实例。然后,当我更改事务中的上下文时,一切都会变得一团糟 似乎我需要暂停活动事务并将当前事务上下文存储在一边,以便在进入另一个作用域时能够清除它,使Spring认为它不再位于事务中,并在需要时强制它为新的作用域创建一个。然后在离开作用域时,我必须恢复先前挂起的事务。不幸的是,我还不能想出一个可行的实现。任何提示,不胜感激 下面是我的一些代码,但它是相当标准的,除了作用域代理 数据源: 平台TracsactionManager:Java Spring范围的代理事务可以通过JPA处理,但不能通过JDBC提交,java,spring,transactions,jdbctemplate,Java,Spring,Transactions,Jdbctemplate,我的情况是,我必须在一个应用程序中处理多个客户端,每个客户端都有单独的数据库。为了支持这一点,我使用了Spring自定义范围,这与内置的请求范围非常相似。用户在每个请求中进行身份验证,并可以基于传递的凭据设置上下文客户端ID。范围界定本身似乎工作正常 因此,我使用自定义作用域为数据源创建一个作用域代理,以支持每个客户机的不同数据库。我可以连接到适当的数据库 然后我为EntityManagerFactory创建了一个作用域代理以使用JPA。这部分看起来也不错 然后,我为PlatformTransa
您是否尝试调试org.springframework.jdbc.datasource.DataSourceUtilsdoGetConnection以查看发生了什么情况?@mrembisz是的;那里似乎一切都很好;使用TransactionSynchronizationManager将数据源绑定到线程;我不能完全确定注册的事务同步回调是否被正确调用,因为在一个请求中有太多对TransactionSynchronizationManager的调用,以至于我在两打之后感到困惑:/1。我认为LocalContainerEntityManagerFactoryBean和JpaTransactionManager不需要自定义范围,因为它们都只是委托给代理的数据源。2.你知道吗?它处理的用例与你的完全相同吗?3.如果启用org.springframework.transaction logger,它不会显示可疑的内容吗?4.如果您将JPA和JDBC更新合并到一个事务中,则两者都不会提交?您是否尝试调试org.springframework.JDBC.datasource.DataSourceUtilsdoGetConnection以查看发生了什么情况?@mrembisz是的,我做了;那里似乎一切都很好;使用TransactionSynchronizationManager将数据源绑定到线程;我不能完全确定注册的事务同步回调是否被正确调用,因为在一个请求中有太多对TransactionSynchronizationManager的调用,以至于我在两打之后感到困惑:/1。我认为LocalContainerEntityManagerFactoryBean和JpaTransactionManager不需要自定义范围,因为它们都只是委托给代理的数据源。2.你知道吗?它处理的用例与你的完全相同吗?3.如果启用org.springframework.transaction log 是不是有可疑的东西?4.如果将JPA和JDBC更新合并到一个事务中,那么这两个事务都没有提交?
<!-- provides database name based on client context -->
<bean id="clientDatabaseNameProvider"
class="com.example.common.spring.scope.ClientScopedNameProviderImpl"
c:clientScopeHolder-ref="clientScopeHolder"
p:databaseName="${base.db.name}" />
<!-- an extension of org.apache.commons.dbcp.BasicDataSource that
uses proper database URL based on database name given by above provider -->
<bean id="jpaDataSource" scope="client"
class="com.example.common.spring.datasource.MysqlDbInitializingDataSource"
destroy-method="close"
p:driverClassName="${mysql.driver}"
p:url="${mysql.url}"
p:databaseNameProvider-ref="clientDatabaseNameProvider"
p:username="${mysql.username}"
p:password="${mysql.password}"
p:defaultAutoCommit="false"
p:connectionProperties="sessionVariables=storage_engine=InnoDB">
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="MYSQL"
p:generateDdl="true"
p:showSql="true" />
<util:properties id="jpaProperties">
<!-- omitted for readability -->
</util:properties>
<bean id="jpaDialect"
class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="com.example.model.core"
p:jpaVendorAdapter-ref="jpaVendorAdapter"
p:dataSource-ref="jpaDataSource"
p:jpaDialect-ref="jpaDialect"
p:jpaProperties-ref="jpaProperties" />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:dataSource-ref="jpaDataSource"
p:entityManagerFactory-ref="entityManagerFactory" />
<tx:annotation-driven proxy-target-class="false" mode="proxy"
transaction-manager="transactionManager" />