pnpm install typeorm-transactional
async function bootstrap() {
initializeTransactionalContext();
const app = await NestFactory.create(AppModule, {
abortOnError: true,
});
await app.listen(3001);
}
bootstrap();
@Module({
imports: [
TypeOrmModule.forRootAsync(
{
useFactory: () => getConfig(),
dataSourceFactory: async function () {
return addTransactionalDataSource(new DataSource(getDataSourceConfig()));
},
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
src/common/database/configuration.ts
export const getConfig = (): TypeOrmModuleOptions => {
return {
type: 'mariadb',
host: process.env.DATABASE_HOST,
port: parseInt(process.env.DATABASE_PORT),
username: process.env.USERNAME,
password: process.env.PASSWORD,
database: process.env.DATABASE,
logging: process.env.LOGGING === 'true',
entities: [process.env.ENTITIES],
synchronize: process.env.SYNCHRONIZE === 'true',
}
}
export const getDataSourceConfig = (): DataSourceOptions => {
return {
type: 'mariadb',
host: process.env.DATABASE_HOST,
port: parseInt(process.env.DATABASE_PORT),
username: process.env.USERNAME,
password: process.env.PASSWORD,
database: process.env.DATABASE,
logging: process.env.LOGGING === 'true',
entities: [process.env.ENTITIES],
synchronize: process.env.SYNCHRONIZE === 'true',
}
}
@Injectable()
export class ProductService {
constructor(
@InjectRepository(Product)
private readonly productRepository: Repository<Product>,
@InjectRepository(Category)
private readonly categoryRepository: Repository<Category>,
@InjectRepository(ProductImage)
private readonly productImageRepository: Repository<ProductImage>,
) {}
@Transactional()
async saveProduct(request: ProductSaveRequest) {
const category = await this.categoryRepository.findOneBy({ id: request.categoryId });
const product = await this.productRepository.save(request.toEntity(category));
const productImages = await this.productImageRepository.save(
request.productImages.map(
(productImage) => ProductImage.of(productImage, product)
));
return ProductResponse.of(category, product, productImages);
}
// ...
}
실행 로그를 보면 로직 첫 부분에서 트랜잭션이 시작되고 로직 종료 시점에 커밋 or 롤백이 되는 것을 확인할 수 있다