Java Spring范围的代理事务可以通过JPA处理,但不能通过JDBC提交

Java Spring范围的代理事务可以通过JPA处理,但不能通过JDBC提交,java,spring,transactions,jdbctemplate,Java,Spring,Transactions,Jdbctemplate,我的情况是,我必须在一个应用程序中处理多个客户端,每个客户端都有单独的数据库。为了支持这一点,我使用了Spring自定义范围,这与内置的请求范围非常相似。用户在每个请求中进行身份验证,并可以基于传递的凭据设置上下文客户端ID。范围界定本身似乎工作正常 因此,我使用自定义作用域为数据源创建一个作用域代理,以支持每个客户机的不同数据库。我可以连接到适当的数据库 然后我为EntityManagerFactory创建了一个作用域代理以使用JPA。这部分看起来也不错 然后,我为PlatformTransa

我的情况是,我必须在一个应用程序中处理多个客户端,每个客户端都有单独的数据库。为了支持这一点,我使用了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:


您是否尝试调试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" />