使用PostgreSQL中的Schema的Hibernate和多租户数据库
背景
我正在开发一个需要支持数千名用户的未来多租户Web应用程序。 该应用程序正在基于Java的Play上构建! MVC框架使用JPA / Hibernate和postgreSQL。
我观看了Guy Naor关于在Rails中编写多租户应用程序的演讲,其中他谈到了多租户的几种方法(数据隔离随着你的列表而减少):
- 每个客户都有一个单独的数据库
- 一个数据库,为每个客户提供单独的模式和表(表名称空间)。
- 一个数据库,包含一组具有客户ID列的表。
我选择了方法#2,其中某种用户ID从请求中解析出来,然后用于访问该用户表空间。 postgres SET search_path TO customer_schema,public
在进行任何查询之前给出SET search_path TO customer_schema,public
命令,以确保客户的表是查询的目标。 这可以通过Play中控制器方法中的@Before
控制器注释轻松完成! (这是Guy在他的rails示例中使用的方法)。 postgres中的search_path与$PATH
在操作系统中的行为完全相同; 真棒!
所有这些听起来都很棒,但是我在JDBC / Hibernate / JPA堆栈上实现它时遇到了困难,因为似乎没有办法在运行时动态切换模式。
问题
如何获得JDBC或Hibernate以支持在运行时动态切换postgres模式?
似乎数据库连接是由连接工厂静态配置的(请参阅: 如何使用hibernate管理一个数据库上的许多模式 )。 我发现类似的问题与每个用户使用多个SessionFactorys的类似答案,但因为我理解SessionFactorys是重量级的对象,所以你可以支持数百个用户,更不用说成千上万的用户,走这条路线是不可信的。
我还没有完全认真地对待上面的#2,但我还没有完全抛弃#3方法。
您可以执行该命令
SET search_path TO customer_schema,public
根据需要,在同一个连接/会话/事务中。 它只是SELECT 1;
类的另一个命令SELECT 1;
。 更多在手册中 。
当然,您也可以为每个用户预设search_path
。
ALTER ROLE foo SET search_path=foo, public;
如果每个用户或其中许多用户具有与其用户名匹配的架构,则可以使用postgresql.conf中的默认设置 :
search_path="$user",public;
更多在此处设置search_path
方法:
search_path如何影响标识符解析和“当前架构”
从Hibernate 4.0开始,鉴别器(customerID),架构和数据库级别本身支持多租户。 请参阅此处的源代码和此处的unit testing。
难点在于,虽然unit testing的文件名是SchemaBasedMultitenancyTest,但实际使用的MultitenancyStrategy是Database。 我找不到任何关于如何使其基于模式工作的示例,但也许unit testing将足以继续……
虽然通过模式进行分片很常见,但请参阅Apartment gem作者的这篇文章 ,其中包含一些缺点。
在Citus,我们通过上面列出的选项#3进行分片,您可以在文档中的用例指南中阅读更多内容。
- 没有基础表的Hibernate实体
- 如何构建一个动态查询,该查询添加了迄今为止的天数,并使用条件API将该日期与另一个日期进行比较?
- Hibernate的会话线程安全吗?
- 我可以使用带有beanvalidation的hibernate实体注释吗?
- 如何在hibernate的名为key的列名中添加反引号
- Java – Hibernateexception – 无法映射反馈
- Hibernate / JPA注释 – 未知实体
- 如何基于NOT条件加入2个实体
- ClassCastException:org.springframework.orm.jpa.EntityManagerHolder无法强制转换为org.springframework.orm.hibernate5.SessionHolder