Pg-promise:更改 db.task() 中的 search_path 是否也会更改在外部运行的查询?

问题描述

假设我有以下代码

db.task(t => {
    return t.none('set search_path to myschema').then(() => {
        return t.any('select * from mytable').then(results => {
            return t.none('set search_path to originalschema').then(() => {
                return results
      })
    })
  })
})

db.task() 之外的查询,碰巧在 db.task() 内的两次 search_path 更改之间运行,是否可以实际访问“myschema”而不是“originalschema”中的数据?

解决方法

db.task() 之外的查询,碰巧在 db.task() 内的两次 search_path 更改之间运行,是否可以实际访问“myschema”而不是“originalschema”中的数据?

没有

SET search_path 是基于会话的操作,即它仅适用于当前连接,任务在其整个执行期间专门分配该连接。

一旦任务完成,它就会释放连接回池。此时,任何获得相同连接的查询都将使用替​​代模式,除非是另一个任务再次设置模式。如果您只在一项任务中设置架构,这会变得很棘手,通常不建议这样做。

这里应该是这样的:

  • 如果您只想在一项任务中访问特殊情况架构,最好在查询中明确指定架构名称。
  • 如果您想为整个应用动态设置自定义架构,最好使用 Initialization Options 的选项 schema。这将通过所有新连接自动传播架构。
  • 如果您想静态设置架构,请there are queries for setting schema permanently

添加:

如果您有一个非常特殊的情况,即您有一个任务需要在替代架构中运行可重用查询,那么您可以在任务的开头设置架构,然后将其恢复到默认架构结束,因此以后获取该连接的任何其他查询都不会尝试使用错误的架构。

额外:

下面的示例创建您自己的 task 方法(我称之为 taskEx),在整个协议中保持一致,它接受新选项 schema,以在任务中设置可选架构:

const initOptions = {
    extend(obj) {
        obj.taskEx = function () {
            const args = pgp.utils.taskArgs(arguments); // parse arguments
            const {schema} = args.options;
            delete args.options.schema; // to avoid error thrown
            if (schema) {
                return obj.task.call(this,args.options,t => {
                    return t.none('SET search_path to $1:name',[schema])
                        .then(args.cb.bind(t,t));
                });
            }
            return obj.task.apply(this,args);
        }
    }
});

const pgp = require('pg-promise')(initOptions);

因此您可以在代码中的任何位置使用:

const schema = 'public';
// or as an array: ['public','my_schema'];

db.taskEx({schema},t => {
    // schema set inside task already;
});

请注意,taskEx 实现假定架构是完全动态的。如果它是静态的,则没有必要在每次任务执行时重新发出 SET search_path,并且您可能只想根据以下检查对新连接执行此操作:

const isFreshConnection = t.ctx.useCount === 0;

但是,在这种情况下,您最好使用初始化选项 schema 代替,如前所述。