【发布时间】:2020-09-07 14:18:44
【问题描述】:
在处理具有多个表和多个数据库操作的大型应用程序时,很难跟踪正在发生的事务。为了解决这个问题,我们首先传递了一个 trx 对象。
事实证明这很混乱。
例如:
async getOrderById(id: string, trx?: Knex.Transaction) { ... }
根据调用getOrderById 的函数,它要么传递trx 对象,要么不传递。上述函数将使用trx,如果它不为null。
一开始这似乎很简单,但它会导致错误,如果您在一个函数中进行事务并调用另一个不使用事务的函数,knex 将与著名的Knex: Timeout acquiring a connection. The pool is probably full. 挂起
async getAllPurchasesForUser(userId: string) {
..
const trx = await knex.transaction();
try {
..
getPurchaseForUserId(userId); // Forgot to make this consume trx, hence Knex timesout acquiring connection.
..
}
基于此,我假设这不是最佳实践,但如果 Knex 开发团队的人可以发表评论,我会很高兴。
为了改进这一点,我们正在考虑改用knex.transactionProvider(),无论我们在哪里执行数据库操作,都可以在整个应用程序中访问它。
网站上的例子似乎不完整:
// Does not start a transaction yet
const trxProvider = knex.transactionProvider();
const books = [
{title: 'Canterbury Tales'},
{title: 'Moby Dick'},
{title: 'Hamlet'}
];
// Starts a transaction
const trx = await trxProvider();
const ids = await trx('catalogues')
.insert({name: 'Old Books'}, 'id')
books.forEach((book) => book.catalogue_id = ids[0]);
await trx('books').insert(books);
// Reuses same transaction
const sameTrx = await trxProvider();
const ids2 = await sameTrx('catalogues')
.insert({name: 'New Books'}, 'id')
books.forEach((book) => book.catalogue_id = ids2[0]);
await sameTrx('books').insert(books);
在实践中,我是这样考虑使用它的:
SingletonDBClass.ts:
const trxProvider = knex.transactionProvider();
export default trxProvider;
Orders.ts
import trx from '../SingletonDBClass';
..
async getOrderById(id: string) {
const trxInst = await trx;
try {
const order = await trxInst<Order>('orders').where({id});
trxInst.commit();
return order;
} catch (e) {
trxInst.rollback();
throw new Error(`Failed to fetch order, error: ${e}`);
}
}
..
我理解正确吗?
另一个实际需要事务的示例函数:
async cancelOrder(id: string) {
const trxInst = await trx;
try {
trxInst('orders').update({ status: 'CANCELED' }).where({ id });
trxInst('active_orders').delete().where({ orderId: id });
trxInst.commit();
} catch (e) {
trxInst.rollback();
throw new Error(`Failed to cancel order, error: ${e}`);
}
}
有人可以确认我是否理解正确吗?更重要的是,如果这是做到这一点的好方法。或者有没有我遗漏的最佳实践?
感谢您的帮助 knex 团队!
【问题讨论】:
标签: node.js postgresql typescript knex.js