NestJS에서 typeorm-transactional를 사용하여 트랜잭션 관리
00. 들어가기 전
필자는 백엔드 개발을 Node(Express)로 시작하였지만, 동아리 활동으로 인해 Spring Boot를 그 후에 접하고 Node에서 Spring Boot처럼 구현할 수 있는 NestJS에 매력을 느껴 지속적으로 사용 중이다.
사실 NestJS를 가장 좋아하지만 Spring boot로 개발해야하는 경우도 어쩔 수 없이 있기에 둘 다 사용하는 편이라 그런 지 NestJS를 사용할 땐 Spring boot의 특정 기능이 부럽고, Spring boot를 사용할 땐 NestJS의 특정 기능이 부러워질 때가 많은 데, 그 중 NestJS를 사용 중에 가장 Spring Boot에서 부러웠던 건 @Transactional 데코레이더였다.
너무나 쉽게 트랜잭션을 관리하게 해주는 기능이라고 생각했는 데, TypeORM에서도 이것과 유사한 기능을 사용할 수 있게하는 라이브러리가 있어 가져와봤다.
typeorm-transactional
A Transactional Method Decorator for typeorm that uses cls-hooked to handle and propagate transactions between different repositories and service methods. Inpired by Spring Trasnactional Annotation and Sequelize CLS. Latest version: 0.5.0, last published:
www.npmjs.com
01. typeorm-transactional
해당 라이브러리는 TypeORM에서도 @Transactional 데코레이터를 제공하여 쉽게 트랜잭션을 관리하게 해준다. 사실 아래 라이브러리에서 가져온 거 같긴 하다. 아래 라이브러리에서는 Repository 패턴을 쉽게 구성하고 트랜잭션을 관리할 수 있게 하는 거 같은 데 필자는 이미 Custom Repository를 구성하였기에, 해당 라이브러리를 사용한다.
이제 바로 진행할 건데 설정이 간단하고 설명이 잘 되어있다.
GitHub - odavid/typeorm-transactional-cls-hooked: A Transactional Method Decorator for typeorm that uses cls-hooked to handle an
A Transactional Method Decorator for typeorm that uses cls-hooked to handle and propagate transactions between different repositories and service methods. Inpired by Spring Trasnactional Annotation...
github.com
02. 적용해보기.
해당 포스팅은 이미 NestJS, MySQL, TypeORM 설정이 되어있다는 가정 하에 진행합니다.
우선 해당 라이브러리를 설치하자.
pnpm install typeorm-transactional
그리고 main.ts에 initializeTransactionalContext 메서드를 이용하여 초기화를 해준다.
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { VersioningType } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
import LoggerService from './global/util/logger/logger.service';
import { initializeTransactionalContext } from 'typeorm-transactional';
async function bootstrap() {
initializeTransactionalContext(); // Initialize TypeORM transaction
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
bufferLogs: true,
snapshot: true,
});
const configService = app.get(ConfigService);
app.setGlobalPrefix('api');
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: '1',
});
app.useLogger(app.get(LoggerService));
app.enableCors();
await app.listen(configService.get<number>('SERVER_PORT'));
}
bootstrap();
그리고 TypeOrmModule을 import하고 있는 Module에서 설정을 변경해야한다. 필자는 AppModule에서 관리하고 있다. 기존의 DB 설정 부분이 아닌 dataSourceFactory 해당 부분을 추가해주면 모든 설정이 종료된다.
TypeOrmModule.forRootAsync({
useFactory() {
return {
type: 'mysql',
host: process.env.DB_HOST,
port: +process.env.DB_PORT,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
entities: ['dist/modules/**/*.entity.js'],
synchronize: true,
logging: true,
logger: 'file',
charset: 'utf8mb4_unicode_ci',
timezone: '+09:00',
};
},
async dataSourceFactory(option) {
if (!option) throw new Error('Invalid options passed');
return addTransactionalDataSource(new DataSource(option));
},
})
설정을 한 후엔 이젠 Spring Boot JPA에서 하는 것과 마찬가지로 @Transactional 데코레이터를 사용하여 트랜잭션을 간단하게 관리할 수 있다!
@Transactional()
public async saveUser(user : User){
await this.userRepository.save(user);
}