Knex/Objection.js多表事务实现:现有代码优化及正确写法问询
正确的Knex/Objection.js事务写法
你这段代码的核心问题是没把操作绑定到事务上下文,导致table1的查询和table2的插入不在同一个事务里,完全没用到事务的原子性保障。修正后的写法如下:
await Table1Model.transaction(async trx => { // 查询table1时绑定事务,只取必要字段,用first()拿单条结果 const room = await this.table1.query(trx) .select('id') .where({ id: this.m_id, is_deleted: false }) .first(); // first()没找到记录会返回undefined,直接判断即可 if (room) { // 插入table2时同样绑定事务 await this.table2.query(trx).insert(newUser); } else { // 无匹配记录时的逻辑,比如抛错终止事务 throw new Error('目标会议室不存在'); } });
优化方案
- 精简查询,提升性能:如果只是判断记录是否存在,没必要查整个字段,用
exists()更高效:await Table1Model.transaction(async trx => { const roomExists = await this.table1.query(trx) .where({ id: this.m_id, is_deleted: false }) .exists(); if (roomExists) { await this.table2.query(trx).insert(newUser); } }); - 完善错误处理:事务里抛错会自动回滚,外层可以加try/catch处理失败场景:
try { await Table1Model.transaction(async trx => { const roomExists = await this.table1.query(trx) .where({ id: this.m_id, is_deleted: false }) .exists(); if (!roomExists) { throw new Error('会议室不存在,终止插入'); } await this.table2.query(trx).insert(newUser); }); } catch (err) { console.error('事务执行失败:', err.message); // 这里可以加自定义错误返回、日志记录等逻辑 } - 利用模型关联简化代码:如果table2和table1有关联(比如table2是table1的子表),可以用Objection的关联方法直接插入:
await Table1Model.transaction(async trx => { const room = await this.table1.query(trx) .findById(this.m_id) .where({ is_deleted: false }); if (room) { // 假设模型里定义了users关联 await room.$relatedQuery('users', trx).insert(newUser); } }); - 确保数据安全:
newUser的字段要和table2的结构匹配,别手动拼接SQL,Objection/Knex会自动处理参数绑定,避免注入风险。
内容的提问来源于stack exchange,提问作者Kumar Arnav
相关产品推荐
相关产品推荐

