升级到 6.2 后 Hibernate 多租户失败

问题描述 投票:0回答:1

我正在将 Spring Boot 项目从 2.7 升级到 3.1.5,其中涉及将 Hibernate 5 升级到 6.2。这完全破坏了我基于模式的多租户设置。我使用 Postgres 12 和 Spring Data JPA,以及各种实体类和 JpaRepository 接口。我用 Testcontainers 进行测试。

我的基于模式的多租户设置使用

MultiTenantConnectionProvider
CurrentTenantIdentifierResolver
的实现,它们是
@Component
Bean。升级后,如果我不使用 Hibernate 属性注册连接提供程序(单独运行时),我只能通过涉及存储库和测试容器的测试;然而,这使得项目无法构建(使用 Maven)。

在 Spring Boot 2.7 中,我必须让两个多租户组件实现

HibernatePropertiesCustomizer
并通过
AvailableSettings.MULTI_TENANT_ ...
向 Hibernate 属性注册自己 (而且我知道
MULTI_TENANT
类型属性本身已在 Hibernate 6 中删除)。这是我能够让应用程序识别多租户组件的唯一方法。在带有 Hibernate 6.2 的 Spring Boot 3.1.5 中,
TenantIdentifierResolver
可以很好地注册自身 - 只是连接提供程序导致测试失败。但如果我不注册它,我的应用程序根本无法构建,并且我没有多租户设置。

注册连接提供者时出现错误:

    org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction
 at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:466)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:601)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
 at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
 at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:164)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)
 at jdk.proxy2/jdk.proxy2.$Proxy228.save(Unknown Source)
 at org.fake.pckge.name.TestContainerTests.saveEntityToRepository(TestContainerTests.java:36)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.hibernate.TransactionException: JDBC begin transaction failed: 
 at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.begin(AbstractLogicalConnectionImplementor.java:78)
 at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:282)
 at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:232)
 at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:83)
 at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:164)
 at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:420)
 ... 85 more
Caused by: java.sql.SQLException: Connection is closed

我尝试以其他方式注册连接提供程序,例如在

HibernateConfig
Bean 中,或在
MultiTenancyJpaConfiguration
中(如 这篇文章 的建议)以及应用程序属性中。无论我在哪里注册,我都会遇到同样的问题。我想知道这是否是先有鸡还是先有蛋的情况,即 Bean 的实例化速度太慢,无法使用正确的模式建立连接。另一个难题是我的
TenantBasedConnectionProvider
依赖于自定义
@Configuration
Bean,它从应用程序 YAML 加载一些属性,例如要使用的模式名称。然而,就像我说的,这在 Spring Boot 2.7 中工作得很好,并且应该是可能的,因为 Hibernate 属性也在应用程序 YAML 中设置。

我能做什么?

java spring-data-jpa multi-tenant spring-boot-3 hibernate-6.x
1个回答
0
投票

我已经解决了。这是一个转移注意力的事情。在调试时,我在所有 Testcontainer 测试都实现的

@Container
接口中引入了
PostgresIntegrationTest
注释。此注释会在第一个测试运行后关闭 Testcontainer。您不能使用
@Container
@ServiceConnection
- 您必须使用
@DynamicPropertyRegistry
并在方法内调用
container.start()

另一个问题是,在

MultiTenantConnectionProvider.getConnection
中,我将连接放在 try 块的括号内,这意味着连接将自动关闭。您必须将其保持打开状态并允许 Hibernate 来管理它

© www.soinside.com 2019 - 2024. All rights reserved.