jOOQ中的动态运行时PostgreSQL模式选择

时间:2015-01-12 22:37:49

标签: java postgresql jooq

Alice和Bob希望Dave开发一个应用程序。他们都希望使用相同的数据类型,但他们都希望保持数据的独立性和安全性。所以Dave开始构建DEV架构。

CREATE TABLE foo (id INT PRIMARY KEY);
CREATE FUNCTION bar(_id INT) RETURNS INT AS $$
    INSERT INTO foo (id) VALUES (_id) RETURNING id;
$$ LANGUAGE SQL;

Dave使用Flyway初始化Alice和Bob的模式,因此它们都具有foo表和bar函数。 Dave使用jOOQ生成java api,并在运行时将DEV模式映射到用户模式。戴夫,以前与他的任何一个客户都没有关系,突然发现自己是鲍勃的侄子。

但爱丽丝和鲍勃后来都回到戴夫身边并要求他为他们写一些自动化。所以Dave决定创建一个可以访问Alice和Bob的模式的机器用户Rob。他可以重用所有相同的jOOQ生成的代码,并且使用foo的所有内容都可以完美地工作,直到自动化尝试执行bar函数 - 错误:关系" foo"不存在。运行时模式映射对函数栏内对foo的无模式引用没有影响。

琐碎的答案是将search_path设置为Rob应该伪装成的用户。这可以在每组jOOQ调用之前手动设置,但这感觉就像那种容易出错,繁琐的代码jOOQ通常会使我们无法编写代码。 Dave可以创建两个用户Rolice和Robob,每个用户都单独配置为访问他们各自的客户端。但这显然很难扩展,特别是在使用连接池时。 Dave选择设置search_path的自定义ConnectionProvider,但这可能是一个非常大的开销,因为search_path查询必须在返回连接之前返回结果。

所以Dave狩猎,询问StackOverflow关于设置search_path的明显问题,并且发现该功能已被删除,出于很好的理由,从3.0版本的jOOQ中删除。但Dave是那种真正喜欢jOOQ优雅的人,感觉必须有比他黑客更好的解决方案。

我不是戴夫,但我当然知道他来自哪里。在jOOQ中,让一个自动化用户与几个相同的用户模式交互,特别是使用包含无模式引用的函数的最佳方法是什么?

如果重要,请关注PostgreSQL 9.3和jOOQ 3.5。戴夫在你想要的任何事情上,因为我在半小时前让他成长。

ConnectionProvider解决方案的相关位:

@Override
public Connection acquire() throws DataAccessException {
    Connection c = dataSource.getConnection();
    try(Statement s = c.createStatement()){
        s.execute("SET search_path = '"+schema+"'");
    }catch(SQLException e){
        throw new DataAccessException("Could not initialize connection", e);
    }
    return c;
}

1 个答案:

答案 0 :(得分:1)

至少目前看来,设置search_path是jOOQ的范围之外的事情。理论上,我们可以在Flyway中使用Java迁移并强制函数内的所有引用都具有显式模式,但这听起来非常痛苦。这使我们无法手动设置搜索路径,可能将其添加到我们的事务管理中,或者编写更智能的ConnectionProvider。

我们的应用程序上有一个非常严格的每查询一次查询模型,因此实际上没有任何事务管理可以添加“set search_path = ...”查询。 ConnectionProvider解决方案似乎是我们的最佳选择。

我们已经有一个用于连接池的自定义ConnectionProvider实现,因此添加逻辑(在问题末尾给出)来设置search_path并不是太麻烦。我们可以通过使用记住当前search_path设置的内容来装饰Connection以及为“set search_path = ...;”加前缀来使其更高效。如果需要的话,在它出门之前的任何声明的前面。我们已经看到每次请求都设置search_path会对性能产生影响,因此在此变为必需之前只是时间问题。好吧,那或者回到我们旧的专有数据库访问层的痛苦。

至少,在我编写并开源连接池/ search_path设置ConnectionProvider之前,我不会接受这个作为答案,希望在我开始使用之前,其他人会想出更好的解决方案。