In this post, we will look at how to perform a NestJS TypeORM Transaction using the TypeORM QueryRunner class. This is also the recommended way of handling transactions in NestJS.

If you are new to using TypeORM with NestJS, refer to this detailed post about NestJS TypeORM Integration.

1 – The Need of Transaction Management

Transactions are one of the most important concepts while dealing with databases. Basically, a transaction is a unit of work. We should treat it as a whole. Either it happens completely or it does not happen.

For example, you can think of transferring money from one account to another. On face value, this process involves multiple steps such as withdrawing money from the first account and then transferring it into the recipient’s account. The transfer fails if even one of the steps fail. Hence, we should handle such operations in the form of transactions.

2 – The ACID Property of Transactions

A transaction must have the below properties. They are commonly known as ACID properties.

  • Atomicity – This means that the operations in a transaction are a single unit that succeed or fail.
  • Consistency – A valid transaction brings the database from one valid state to another.
  • Isolation – Transactions should be isolated. In other words, transactions can occur concurrently. Basically, valid transactions don’t cause inconsistent state. Also, the intermediate state of transaction should be invisible to other transactions.
  • Durability – Changes made by a transaction should be durable. In other words, the changes should survive even a system failure.

3 – Handling NestJS TypeORM Transactions

The TypeORM package comes with the Connection class. We will inject this class into our LibraryService example.

See below code:

constructor(
@InjectRepository(Book)
    private bookRepository: Repository<Book>,
    private connection: Connection
){}

The Connection class resides in the typeorm package. The below import statement will be needed.

import { Connection } from "typeorm";

The Connection object does not represent a single database connection. It basically points to a pool of connections. To refer to a single database collection, we use the QueryRunner class. Basically, every instance of the QueryRunner is a connection.

4 – Using QueryRunner Class

We can now use the Connection object to create a transaction.

See below example:

async createMultipleBooks(books: Book[]) {
   const queryRunner = this.connection.createQueryRunner();

        await queryRunner.connect();
        await queryRunner.startTransaction();

        try {
            await queryRunner.manager.save(books[0]);
            await queryRunner.manager.save(books[1]);

            await queryRunner.commitTransaction();
        }catch (err) {
            await queryRunner.rollbackTransaction();
        }finally {
            await queryRunner.release();
        }
}

Basically, we use an instance of QueryRunner to establish a connection and start a transaction. Then, we save all the books (in this case 2 books) as part of the same transaction. If something goes wrong, we rollback everything. Else, we commit the transaction and release the connection.

Conclusion

With this, we are done with NestJS TypeORM Transaction using QueryRunner. You can find the code for the same on Github.

If you have any comments or queries about the post, please feel free to write in the comments section below.


Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *