简体   繁体   English

使用PostgreSQL中的Schema的Hibernate和多租户数据库

[英]Hibernate and Multi-Tenant Database using Schemas in PostgreSQL

Background 背景

I am working on a future multi-tenant web application that will need to support thousands of users. 我正在开发一个需要支持数千名用户的未来多租户Web应用程序。 The app is being built on top of the Java based Play! 该应用程序正在基于Java的Play上构建! MVC Framework using JPA/Hibernate and postgreSQL. MVC框架使用JPA / Hibernate和postgreSQL。

I watched Guy Naor's talk on Writing Multi-tenant Applications in Rails in which he talks about a few approaches to multi-tenancy (data isolation decreases as you go down the list): 我观看了Guy Naor关于在Rails编写多租户应用程序的演讲,其中他谈到了多租户的几种方法(数据隔离随着你的列表而减少):

  1. Each customer has a separate database 每个客户都有一个单独的数据库
  2. One database with separate schemas and tables (table namespaces) for each customer. 一个数据库,为每个客户提供单独的模式和表(表名称空间)。
  3. One database with 1 set of tables with customer id columns. 一个数据库,包含一组具有客户ID列的表。

I settled on approach #2, where a user id of some sort is parsed out of a request and then used to access that users tablespace. 我选择了方法#2,其中某种用户ID从请求中解析出来,然后用于访问该用户表空间。 A postgres SET search_path TO customer_schema,public command is given before any query is made to make sure the customer's tables are the target of a query. postgres SET search_path TO customer_schema,public在进行任何查询之前给出SET search_path TO customer_schema,public命令,以确保客户的表是查询的目标。 This is easily done with @Before controller annotations in controller methods in Play! 这可以通过Play中控制器方法中的@Before控制器注释轻松完成 (this is the approach Guy used in his rails example). (这是Guy在他的rails示例中使用的方法)。 The search_path in postgres acts exactly like the $PATH does in an OS; postgres中的search_path与操作系统中的$PATH完全相同; awesome! 真棒!

All this sounded great, but I immediately ran into difficulties in implementing it on top of a JDBC/Hibernate/JPA stack because there doesn't seem to be a way to dynamically switch schemas at runtime. 所有这些听起来都很棒,但是我在JDBC / Hibernate / JPA堆栈上实现它时遇到了困难,因为似乎没有办法在运行时动态切换模式。

The Problem 问题

How do I get either JDBC or Hibernate to support dynamically switching postgres schemas at runtime? 如何获得JDBC或Hibernate以支持在运行时动态切换postgres模式?

It seems database connections are statically configured by a connection factory (see: How to manage many schemas on one database using hibernate ). 似乎数据库连接是由连接工厂静态配置的(请参阅: 如何使用hibernate管理一个数据库上的许多模式 )。 I have found similar questions with similar answers of using multiple SessionFactorys per user, but since I understand SessionFactorys are heavy weight objects so it's implausible that you could support hundreds of users, let alone thousands of users, going this route. 我发现类似的问题与每个用户使用多个SessionFactorys的类似答案,但因为我理解SessionFactorys是重量级的对象,所以你可以支持数百个用户,更不用说成千上万的用户,走这条路线是不可信的。

I haven't committed myself completely to approach #2 above, but I haven't quite abandoned it for approach #3 quite yet either. 我还没有完全认真地对待上面的#2,但我还没有完全抛弃#3方法。

You can execute the command 您可以执行该命令

SET search_path TO customer_schema,public

as often as you need to, within the same connection / session / transaction. 在同一个连接/会话/事务中,根据需要经常使用。 It is just another command like SELECT 1; 它只是SELECT 1;类的另一个命令SELECT 1; . More in the manual here . 更多在手册中

Of course, you can also preset the search_path per user. 当然,您也可以为每个用户预设search_path

ALTER ROLE foo SET search_path=foo, public;

If every user or many of them have a schema that matches their user name, you can simply go with the default setting in postgresql.conf : 如果每个用户或其中许多用户具有与其用户名匹配的模式,则可以使用postgresql.conf中默认设置

search_path="$user",public;

More ways to set the search_path here: 更多在此处设置search_path方法:
How does the search_path influence identifier resolution and the "current schema" search_path如何影响标识符解析和“当前架构”

While sharding by schema is common, see this post from the Apartment gem authors covering some drawbacks. 虽然通过模式进行分片很常见,但请参阅Apartment gem作者的这篇文章 ,其中包含一些缺点。

At Citus, we shard via option #3 listed above, and you can read more in our use-case guide in the Documentation. 在Citus,我们通过上面列出的选项#3进行分片,您可以在文档中的用例指南中阅读更多内容。

As of Hibernate 4.0, multi-tenancy is natively supported at the discriminator (customerID), schema, and database level. 从Hibernate 4.0开始,鉴别器(customerID),架构和数据库级别本身支持多租户。 See the source code here , and the unit test here . 请在此处查看源代码,并在此处查看单元测试。

The difficulty is that, while the unit test's file name is SchemaBasedMultitenancyTest, the actual MultitenancyStrategy used is Database. 难点在于,虽然单元测试的文件名是SchemaBasedMultitenancyTest,但实际使用的MultitenancyStrategy是Database。 I can't find any examples on how to make it work based on schema, but maybe the unit test will be enough to go on... 我找不到任何关于如何使其基于模式工作的示例,但也许单元测试将足以继续......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM