如有必要,我可以缩短帖子
我使用pg-promise事务插入“设备”及其所有部分(例如系统,磁盘等)。交易有效... 但仅是第一次。之后,我的服务器将无法再与数据库进行交互(无论是插入还是选择)。
这是具有以下步骤的pg-monitor输出
Thu Jul 11 2019 14:26:57 GMT+0200 (GMT+02:00) : server is listening on 9000 14:27:11 connect(hidden@hidden); useCount: 0 14:27:11 insert into "public"."roles"("name") values('Test') RETURNING * 14:27:11 disconnect(hidden@hidden) 14:27:15 connect(hidden@hidden); useCount: 1 14:27:15 insert into "public"."roles"("name") values('Test2') RETURNING * 14:27:15 disconnect(hidden@hidden) 14:27:18 connect(hidden@hidden); useCount: 2 14:27:18 tx(Insert-New-Device)/start 14:27:18 tx(Insert-New-Device): begin 14:27:18 tx(Insert-New-Device): insert into "public"."devices"("smanufacturer") values('HP') RETURNING * 14:27:18 tx(Insert-New-Device): insert into "public"."systems"("deviceid","distributionid","archid","smanufacturer") values(15,3,2,'Microsoft Corporation') RETURNING * 14:27:18 tx(Insert-New-Device): commit 14:27:18 tx(Insert-New-Device)/end; duration: .046, success: true 14:27:18 disconnect(hidden@hidden) 14:27:20 connect(hidden@hidden); useCount: 3 14:27:20 tx(Insert-New-Device)/start 14:27:20 tx(Insert-New-Device): savepoint level_1 14:27:20 error: SAVEPOINT can only be used in transaction blocks tx(Insert-New-Device): savepoint level_1 14:27:20 tx(Insert-New-Device)/end; duration: .011, success: false 14:27:20 disconnect(hidden@hidden)
devices.add
丢
错误:SAVEPOINT只能在事务块中使用
roles.add
丢
错误:查询释放的连接或丢失的连接
问题出在我的存储库中。在pg-promise-demo中,每个存储库都导出类,因此DB初始化在扩展事件中使用new
关键字来创建它们。
我的仓库不是课程。我试图将它们更改为类,并且有效
./ db / repos / devices.js
'use strict';
var Database = null, pgp = null, Collections = null;
async function add(params) {
return Database.tx('Insert-New-Device', async t => {
let system = null;
const query = pgp.helpers.insert(params.data.device, Collections.insert) + " RETURNING *";
let device = await t.one(query);
// if a system is present, insert with diviceId and return
if(params.data.system) {
params.data.system.deviceid = device.deviceid;
system = await t.systems.InsertOne(params);
}
return {device, system};
})
.catch(ex => {
throw ex;
});
}
function createColumnsets() { /* hidden for brevity */ }
// rpc methods
const expose = {
'devices.insert': add
}
const DevicesRepository = {
expose, // expose methods as "rpc methods"
InsertOne: add // internal use (by another repo for example : Database.devices.InsertOne())
};
module.exports = (db, pgpLib) => {
Database = db;
pgp = pgpLib;
Collections = createColumnsets();
return DevicesRepository;
}
./ db / index.js.js
'use strict';
const promise = require('bluebird');
const repos = {
Roles: require('./repos/roles'),
Systems: require('./repos/systems'),
Devices: require('./repos/devices')
}
const config = require('./conf');
const initOptions = {
promiseLib: promise,
extend(obj, dc) {
obj.roles = repos.Roles(obj, pgp);
obj.systems = repos.Systems(obj, pgp);
obj.devices = repos.Devices(obj, pgp);
}
};
const pgp = require('pg-promise')(initOptions);
const monitor = require('pg-monitor');
monitor.attach(initOptions);
const db = pgp(config);
const methods = Object.assign({}, db.roles.expose, db.systems.expose, db.devices.expose );
module.exports = {
methods
}
devices.js
'use strict';
class RolesRepository {
constructor(db, pgp) {
this.Database = db;
this.pgp = pgp;
this.Collections = createColumnsets(pgp);
this.expose = {
'roles.insert': this.InsertOne.bind(this)
}
}
makeInsertQuery(role) {
return this.pgp.helpers.insert(role, this.Collections.insert);
}
async InsertOne(params) {
let query = this.makeInsertQuery(params.data);
if(params.return) query += " RETURNING *";
return this.Database.any(query)
.then(data => { return data; })
.catch(ex => { throw ex; });
}
}
function createColumnsets(pgp) { /* hidden for brevity */ }
module.exports = RolesRepository
./ db / index.js
'use strict';
const promise = require('bluebird');
//const repos = require('./repos'); // ./repos/index.js
const repos = {
Roles: require('./roles'),
Systems: require('./systems'),
Devices: require('./devices'),
};
const config = { /* hidden */ };
const initOptions = {
promiseLib: promise,
extend(obj, dc) {
obj.roles = new repos.Roles(obj, pgp);
obj.systems = new repos.Systems(obj, pgp);
obj.devices = new repos.Devices(obj, pgp);
}
};
const pgp = require('pg-promise')(initOptions);
const monitor = require('pg-monitor');
monitor.attach(initOptions);
const db = pgp(config);
// expose db methods as rpc call
const methods = Object.assign({},
db.roles.expose,
db.systems.expose,
db.devices.expose,
);
module.exports = {
methods
}
答案 0 :(得分:0)
我不认为您显示的是完整的代码,因为在pg-promise交易级别中,您所遇到的问题类型是不可能的。它无法在事务外执行SAVEPOINT
。
但是,有一种方法可以破解它,这可能会破坏这种库,而且我高度怀疑这是您所做的,以某种方式...
当我们使用方法task
执行任务或通过方法tx
执行事务时,该方法会创建一个临时连接上下文,该上下文将您作为执行查询的回调参数。
以这种方式完成,因此,当回调完成时,上下文将自动销毁。而且,如果您以某种方式在回调函数之外公开了该上下文,并开始对其执行查询,则会破坏连接上下文逻辑。
打破它的一种方法是执行一个使用上下文的异步函数,而不是在回调完成时完成它。然后,您可能会遇到这种类型的错误-Querying against a released or lost connection
,它告诉您上下文已消失/已释放,并且您仍在尝试对它执行查询。
您需要确保不要在回调函数之外使用连接上下文,因为在该函数中无法使用该连接上下文,并且以这种方式使用它的结果可能无法预测。