我有一个多租户应用程序,我需要在运行时更改架构名称,这样它就会被共享数据库分离架构 SaaS 设计。
因为创建一个EntityManagerFactory非常昂贵,我想创建EMF应用程序作用域,并在启动EntityManger之后在每个DB调用之前指定架构。我正在使用 Postgresql 8.1并且因为Postgesql在设置数据库连接时不支持模式选择,我认为从表中查询不同模式的唯一方法是查询' SET search_path =“在进行所需的数据库调用之前,my.schema“”。
我试过了;
StringBuilder sb = new StringBuilder();
sb.append("SET search_path TO my.schema");
entityManager_.createNativeQuery(sb.toString()).executeUpdate();
我有一个例外,说' java.lang.IllegalStateException:你不能在这个查询上调用executeUpdate()。这是不正确的查询类型'
我使用 eclipselink 作为PersistenceProvider, glassfish 作为应用程序管理员
无论如何我可以完成这件事吗?
如果有更好的方法可以实现这一点,我愿意接受任何建议
提前致谢
答案 0 :(得分:2)
由于您正在使用每个架构的租户,您是否还使用租户特定的数据库登录角色(用户ID)?如果是这样,您可以将默认搜索路径绑定到您的用户:
ALTER USER thetenant SET search_path = 'thetenant';
如果你也:
REVOKE ALL ON SCHEMA thetenant FROM public;
GRANT ALL ON SCHEMA thetenant TO tenant;
您将在更大程度上将用户彼此隔离,但他们仍会在pg_catalog
和INFORMATION_SCHEMA
中看到相关内容。
这要求您为每个租户使用登录角色。在连接池处于运行状态时,这可能很困难,因为Java连接池通常无法切换池连接的用户ID,并且必须为每个用户ID保留一个池。 PostgresSQL的SET SESSION AUTHORISATION
语句非常有用,允许您以单个主用户身份登录,然后切换到特定作业所需的用户,但我不知道是否有任何Java池直接支持它。您可以使用SET SESSION AUTHORISATION
知道的PgBouncer和PgPool-II之类的外部连接池,或者查看是否有任何方法可以编写拦截器,这样您就可以在连接时发出SET SESSION AUTHORISATION
连接游泳池,以及RESET SESSION AUTHORISATION
,当他们重新登记时。
即使您不能使用基于角色的访问,我也会尝试使用与您的搜索路径相同的方法:看看您是否可以通过在连接池中检出连接时捕获连接来获取连接池的帮助对于任务,并在发布时检查它们。但是,如何做到这一点取决于连接池,你可能不想深入了解它的具体细节。
顺便说一句,你为什么要使用PostgreSQL这样的史前版本?我不知道为什么EclipseLink拒绝你的命令。从表面看,它看起来很合理。您是否也使用其他东西的古代版本?您使用哪种Glassfish和EclipseLink版本?