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

Pg-promise: does changing the search_path inside a db.task() also change it for queries running outside?

假设我有以下代码:

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'?

Could a query outside of db.task(), that happened to run in between of the two search_path changes inside db.task(), actually access the data in 'myschema' instead of '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 :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