【发布时间】:2020-04-07 11:24:13
【问题描述】:
我正在构建一个包含多个租户(即客户)的企业应用程序 (SaaS)。同一功能的不同客户之间的数据存储在同一张表中,我使用名为“site_id”的列来定义数据的所有权。它看起来像这样:
PurchaseOrder:
- int id
- int site_id
- String product_name
- int quantity
在每个请求中,过滤器都会处理会话信息以确定该用户可以访问哪个站点。这些数据存储在一个静态线程局部变量中,该变量可以从名为Set<Integer> RequestSiteScope.getSiteIds() 的静态方法中检索。
现在对于自动创建的存储库的“findAll”查询,它们也将返回其他客户的数据。
比如我现在有这样的界面
public interface PurchaseOrderRepository implements CrudRepository<PurchaseOrder, int> {
List<PurchaseOrder> findAll();
}
我正在处理一个用户的请求,我知道该用户只能访问 3,4 的 site_id。我想让findAll 只使用site_id in (3, 4) 标准返回数据。 SQL 应该看起来像 select * from purchase_order where site_id in (?, ?); 和参数 3, 4。
当然,我可以手动创建每个查询以始终添加where site_id = ? 子句,但这不仅乏味,而且很容易被我未来的队友忘记。我查看了@Query 注释,但它无济于事,因为我无法将动态变量(site_id)放入其中。
有没有一种方法可以更改 Spring 的逻辑,该逻辑负责神奇地实现这些存储库方法,以便我可以在我的 where 子句中注入一条动态信息(来自线程本地类静态变量)以编程方式?
这个概念有点像 Ruby on Rails ActiveRecord scope 的概念,带有 lamda 的味道。理想情况下,所有涉及带有“site_id”的表的查询都将自动包含此条件,除非涉及某些特殊过程(功能块注释禁用此)。
到目前为止,我一直在研究这些选项,但尚未决定结果:
- 规范执行器 (Spring Boot & JPA: Implementing search queries with optional, ranged criteria)
- AOP 拦截器 (https://www.baeldung.com/hibernate-interceptor)
更新:本文提供了Spring中多租户的所有三种解决方案:https://medium.com/swlh/multi-tenancy-implementation-using-spring-boot-hibernate-6a8e3ecb251a
【问题讨论】:
-
您是否使用共享模式来实现多租户?您如何区分每个客户
-
@secretsuperstar 它是通过一个名为 site_id 的列,它基本上是客户 ID
标签: spring-boot spring-data-jpa hibernate-criteria