In TypeORM, transactions can be handled in various ways, with the most common approach being the use of the @Transaction() decorator or directly using queryRunner. However, to implement transaction callbacks, we typically consider directly using EntityManager or queryRunner to manually control the start and end of transactions, ensuring specific logic is executed at different stages of the transaction.
Using EntityManager Approach
Here is an example using EntityManager that includes transaction callbacks:
typescriptimport { getManager } from 'typeorm'; async function updateUserAndLogTransaction(userId: number, newUserData: any) { const entityManager = getManager(); await entityManager.transaction(async transactionalEntityManager => { try { // Update user information await transactionalEntityManager.update(User, userId, newUserData); // Log transaction const log = { userId: userId, message: 'User data updated successfully' }; await transactionalEntityManager.insert(Log, log); // Transaction callback, such as sending notifications console.log('Transaction executed successfully; you can execute callback functions here, such as sending notifications.'); } catch (error) { console.error('Transaction execution failed: ', error); // Error callback handling throw error; // Rethrow the error to ensure the transaction rolls back } }); }
Using QueryRunner Approach
If more granular control is needed, such as checking query status during the transaction or executing multi-stage operations, use QueryRunner:
typescriptimport { getConnection } from 'typeorm'; async function processJob() { const connection = getConnection(); const queryRunner = connection.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { // First step operation await queryRunner.manager.save(...); // Decide subsequent steps based on the first step's result if (someCondition) { await queryRunner.manager.save(...); } // Execute callback someCallbackFunction(); // Commit transaction await queryRunner.commitTransaction(); } catch (error) { // Rollback transaction await queryRunner.rollbackTransaction(); // Error callback handling errorCallbackFunction(); } finally { // Release queryRunner await queryRunner.release(); } }
In this example, someCallbackFunction() and errorCallbackFunction() are callback functions triggered based on different conditions during the transaction. This approach provides developers with the maximum flexibility to control transactions, including executing different operations and callbacks based on business logic at various stages of the transaction.
Summary
In TypeORM, manually controlling transactions enables the execution of complex logic and transaction callbacks. You can execute any business logic before or after the transaction commit as needed, which is particularly useful for handling business processes requiring multi-step confirmations and complex state management.