Mid #typeorm#transaction#repository#queryrunner
Transaction trong NestJS với TypeORM: DataSource, QueryRunner và repository pattern
⚡ Trả lời nhanh
Dùng dataSource.transaction(async manager => ...) hoặc QueryRunner (connect, startTransaction, commit/rollback, release) và thao tác qua manager/queryRunner.manager cùng một connection. Gọi repository inject sẵn sẽ nằm ngoài transaction. Quên release() sẽ leak connection.
@Injectable()
export class OrdersService {
constructor(private dataSource: DataSource) {}
async checkout(userId: number, items: Item[]) {
return this.dataSource.transaction(async (manager) => {
const order = await manager.save(Order, { userId });
for (const i of items) {
await manager.decrement(Stock, { sku: i.sku }, 'qty', i.qty);
await manager.save(OrderItem, { orderId: order.id, ...i });
}
return order; // lỗi ném ra thì tự rollback
});
}
}
QueryRunner cho kiểm soát thủ công:
const qr = this.dataSource.createQueryRunner();
await qr.connect(); await qr.startTransaction();
try { /* qr.manager.save(...) */ await qr.commitTransaction(); }
catch (e) { await qr.rollbackTransaction(); throw e; }
finally { await qr.release(); }
this.userRepo.save()(repository inject) dùng connection khác, không thuộc transaction; phải dùngmanager.getRepository(User).- Muốn service không phụ thuộc DataSource, bọc bằng unit-of-work hoặc dùng thư viện như
typeorm-transactional(dựa trên AsyncLocalStorage). - Chọn isolation level phù hợp (
'SERIALIZABLE', v.v.) và lock (pessimistic_write) khi tránh race.