我已经在 C# 和 NHibernate 中解决了类似的问题,但似乎您的概念问题不仅仅与特定技术相关。
我们希望为我们的“主要聚合”的不同实例分离表。不是因为多租户,而是为了避免某些主聚合影响另一个主聚合时的性能损失(例如,由于执行第一个“主聚合”的更新查询导致表锁定,因此第二个“主聚合”的读取查询无法读取任何内容)。
我们做了什么:
使用可参数化的表名创建 SQL 脚本,例如 MY_TABLE_{0}
一旦创建了新的“主要聚合”(在您的案例中注册了新用途),第一个项目符号的脚本将使用替换的占位符执行。我们有一个表,其中标识符以原子方式递增,例如,它执行类似CREATE TABLE MY_TABLE_412
...
我们以相同的方式使用命名查询。一旦我们的项目开始,一项服务的代码为每个“主要聚合”创建了一个会话工厂。这段代码为所有“主要聚合”预编译了命名查询。我们存储Dictionary <"main aggregate"_id, named queries>
我们包装了会话工厂和存储库,因此每个执行的查询都需要“主聚合”的标识符。因此,当有人MyPrettyNamedQuery
与“主聚合”ID 一起调用时,该服务会找到正确编译的命名查询并针对连接执行该查询。所以查询确实使用了正确的表,例如SELECT name FROM MY_TABLE_412
我们将这种方法调整到我们的应用程序使用共享表的状态,其中数据库包含一个用于所有“主要聚合”的表,但对于性能关键的子聚合,我们可以使用所描述的方法,使用更多表来获取更多主要聚合。
我们的应用程序已投入生产 3 年,没有客户拒绝授予使用 DB 权限来创建表。
我不确定 java 的 Hibernate 是否包含对此功能的一些支持,但 C# 没有,所以我们需要编写它。
我不建议使用一些“tenant_id”,因为它不安全,你不能将表/模式移动到不同的数据库节点(在可伸缩性的情况下),或者它会带来令人不快的性能问题(我已经写过它) .