在使用Spring Data Repository之前更改当前模式 – 多租户

huangapple go评论79阅读模式
英文:

Change current schema before using spring data Repository - Multi tenancy

问题

我正在使用一个多租户的Spring Boot Web应用程序,该应用程序从数据库中读取一些数据。

我已经建立了基于每个租户的模式,实现了MultiTenantConnectionProvider和CurrentTenantIdentifierResolver,以便根据租户设置连接。租户是使用ThreadLocal变量解析的,该变量在一个Filter中设置(通过扩展OncePerRequestFilter构建)。

然而,我需要解决一个特定的情况,在这种情况下我在过滤器中无法获取租户信息。然而,在稍后在服务中处理请求时,我可以获取到租户信息,但是这时候实体管理器已经被设置(根据Spring源代码,似乎是由OpenSessionInViewFilter完成的),以使用默认模式,并且我所有的查询都失败了,因为默认模式不包含我需要的数据。

我的问题是,当Hibernate过滤器已经设置了会话后,我如何在服务级别上设置实体管理器,使其指向特定于租户的模式?我可以执行类似于以下代码的过滤器(OpenSessionInViewFilter)正在执行的操作:

   EntityManager entityManager = entityManagerFactory.createEntityManager();
   TransactionSynchronizationManager.bindResource(entityManager, new EntityManagerHolder(entityManager));
   //在我使用完repositories后解除绑定

但我在思考是否这样做是正确的方式,或者是否有任何其他更好、更简便、有文档记录的方法。

英文:

I am using a multi tenant spring boot web application which reads some data from a database.

I have built schema per tenant model, implementing MultiTenantConnectionProvider and CurrentTenantIdentifierResolver to set connections based on the tenant. The tenant is resolved using a ThreadLocal variable, set in a Filter (built by extending OncePerRequestFilter).

However, I need to solve for a specific case where I do not get the tenant information at the filter. I can however, get the tenant information later while processing the request in a service, but by this time the entity manager is set (seems to be done by OpenSessionInViewFilter looking at spring sources) to use the default schema and all my queries fail because the default schema do not contain the data I need.

My question is, how do I set the entity manager to point to the tenant specific schema at service level, after the hibernate filter has already set the session? I could do whatever the filter (OpenSessionInViewFilter) is doing, something like the below:

   EntityManager entityManager = entityManagerFactory.createEntityManager();
   TransactionSynchronizationManager.bindResource(entityManager, new EntityManagerHolder(entityManager));
   //unbind once I am done using the repositories

But I was thinking if this is the right way or if there is any other better, easier, documented way.

答案1

得分: 0

       EntityManager entityManager = entityManagerFactory.createEntityManager();
       TransactionSynchronizationManager.bindResource(entityManager, new 
       EntityManagerHolder(entityManager));

上述代码对我无效。然而,我找到了一种解决方法 - 通过在不同的线程中运行我的任务(我只是创建了一个固定的线程池执行器并提交了我的任务),并在 ThreadLocal 对象中设置新的租户,我能够实现我想要的效果。通过正确的 CurrentTenantIdentifierResolver 和 MultiTenantConnectionProvider 实现,与预期的租户架构建立了连接。

英文:
   EntityManager entityManager = entityManagerFactory.createEntityManager();
   TransactionSynchronizationManager.bindResource(entityManager, new 
   EntityManagerHolder(entityManager));

The above didn't work for me. However, I found a workaround - by running my task in a different thread (I just created a fixed thread pool executor and submitted my tasks) and setting the new tenant in a ThreadLocal object, I was able to achieve what I wanted. With the right CurrentTenantIdentifierResolver and MultiTenantConnectionProvider implementations, a connection to the expected tenant schema got established.

huangapple
  • 本文由 发表于 2020年10月14日 01:48:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/64340512.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定