如何使用 Spring Data Jpa 启用多租户

Posted

技术标签:

【中文标题】如何使用 Spring Data Jpa 启用多租户【英文标题】:How to enable Multitenancy with Spring Data Jpa 【发布时间】:2017-10-23 10:51:16 【问题描述】:

背景:我正在构建一个多租户 SaaS 应用程序,并选择了单一数据库、共享架构作为多租户方法。每个表都有一个鉴别列“tenantId”来隔离租户数据。我使用 Spring Boot 作为应用程序框架,并将 Spring Data JPA 用于数据层,并将 Hibernate 作为 JPA 提供程序。我真的很喜欢 spring data 帮助消除样板代码的方式,并且目前已经对如下所示的存储库进行了编码,

@Repository
public interface UserRepository extends JpaRepository<User,Long>


以及以下服务,

public class UserService
    @Autowired
    private UserRepository userRepo;
    public User getUser()
        User user = userRepo.findOne(id);
    

问题陈述:当我想获得用户时,我想获得特定组织的用户。我想知道如何添加租户标准,我不想编写自定义存储库实现,因为这会引入样板代码。

尝试的解决方案:

i) Hibernate Interceptor - onPrepareStatememt:这没什么用,因为 sql 是一个字符串,我不想进行字符串操作。

ii) 使用 Spring AOP 启用 Hibernate 过滤器:使用 @Filter 注释实体并尝试在会话中设置过滤器。这不起作用,因为从不调用方面。

@AfterReturning(pointcut = "execution(* org.hibernate.jpa.internal.EntityManagerImpl.OpenSession(..))", returning = "session")
public void forceFilter(JoinPoint joinPoint, Object session) 

    Session hibernateSession = (Session) session;
    session.enableFilter("tenantFilter")

hibernate 过滤器听起来像是一种很有前途的方法,但我在尝试提出一个可行的解决方案时有点碰壁。我想知道是否有另一种方法可以在 Spring 数据内部用于查询数据的会话中启用休眠过滤器。

【问题讨论】:

显然 AOP 将不起作用,因为切入点永远不会匹配...EntityManagerFactory 用于获取EntityManager 而不是Session,它是createEntityManager。返回的EntityManager 可以将unwrap 编辑为Session 以启用过滤器。但是,启用它后,您还必须将正确的tenantId 设置为参数。 【参考方案1】:

我在博客中提到了 Multi-tenant applications using Spring Boot, JPA, Hibernate and Postgres,尽管我采用了每个租户的 DB 方法,但您使用的 DISCRIMINATOR(用于指定不同租户的一个或多个表列)方法最有可能需要较少的配置。

查看CurrentTenantIdentifierResolver 实现 (TenantDvdRentalIdentifierResolverImpl.java)、DvdRentalMultiTenantInterceptor.java Spring MVC 拦截器和 DvdRentalTenantContext.java 使用ThreadLocal 存储/传递tenantId。

【讨论】:

看起来 hibernate 还没有实现基于 DISCRIMINIATOR 的多租户策略,问题 (hibernate.atlassian.net/browse/HHH-6054) 仍然存在。 我相信 Hibernate 5 可以

以上是关于如何使用 Spring Data Jpa 启用多租户的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data Jpa如何实现审计和乐观锁功能

Spring Data Jpa如何实现审计和乐观锁功能

Spring Data JPA事务支持

如何使用 Hibernate JPA 和 Spring Framework 启用加载时间/运行时编织

使用 spring-data-jpa 获取这些数据如何更正确?

处理 JPA 规范和 spring-data-jpa 时如何使用声明 Stream 作为返回类型