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
。
假设我有以下代码:
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
。