본문 바로가기

Development/TIL

Typeorm Transaction

실전 프로젝트 'MovieWiki' 2주차가 진행중이다.

유저가 본인이 좋아하는 영화에 좋아요를 누르면 해당 영화의 like 숫자를 1 증가시키고

반대로 좋아요를 취소하면 like 숫자를 1 감소시키는 기능을 구현하고 있다.

 

정리하면 유저가 특정 영화에 좋아요를 누르면 2개의 기능이 동작을 해야한다.

1. 해당 유저의 userId와 영화의 movieId를 참조하여 Like 테이블에 데이터를 생성 또는 삭제

2. 해당 영화의 movieId를 참조하여 movie 테이블의 likes 컬럼이 1 증가 또는 1 감소

 

1번과 2번 중에 어느 한쪽만 실패하거나 성공을 하면 안되니까 transation을 사용해야한다.

이전에 클론코딩을 할 때 node.js에서 transation을 적용해본적은 있지만 nestJS에서는 처음이라

구글링을 하여 공식 문서와 다른 개발 일지를 참고하였다.

 

방법은 3가지가 있었다.

  • EntityManager를 사용한 트랜잭션 생성 및 사용
  • QueryRunner를 이용한 트랜잭션 제어
  • Transaction 데코레이터 사용 (공식문서에서 권장하는 방법은 아니라고 함)

 

EntityManager를 사용하는 예시

await myDataSource.transaction(async (transactionalEntityManager) => {
    // execute queries using transactionalEntityManager
})

또는

await myDataSource.manager.transaction(async (transactionalEntityManager) => {
    // execute queries using transactionalEntityManager
})

 

 

격리수준 설정 예시

await myDataSource.manager.transaction(
    "SERIALIZABLE",
    (transactionalEntityManager) => {},
)

 

 

QueryRunner를 이용한 트랜잭션 제어

// create a new query runner
const queryRunner = dataSource.createQueryRunner()

// establish real database connection using our new query runner
await queryRunner.connect()

// now we can execute any queries on a query runner, for example:
await queryRunner.query("SELECT * FROM users")

// we can also access entity manager that works with connection created by a query runner:
const users = await queryRunner.manager.find(User)

// lets now open a new transaction:
await queryRunner.startTransaction()

try {
    // execute some operations on this transaction:
    await queryRunner.manager.save(user1)
    await queryRunner.manager.save(user2)
    await queryRunner.manager.save(photos)

    // commit transaction now:
    await queryRunner.commitTransaction()
} catch (err) {
    // since we have errors let's rollback changes we made
    await queryRunner.rollbackTransaction()
} finally {
    // you need to release query runner which is manually created:
    await queryRunner.release()
}

 

 

likes.service.ts에 QueryRunner 적용

import { Injectable, BadRequestException } from '@nestjs/common';
import { LikeRepository } from './like.repository';
import { DataSource } from 'typeorm';

@Injectable()
export class LikeService {
    constructor(
        private readonly likeRepository: LikeRepository,
        private readonly dataSource: DataSource
    ) { }

    async updateLike(movieId: number, userId: number): Promise<any> {
        const queryRunner = this.dataSource.createQueryRunner();

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

        try {
            const like = await this.likeRepository.findOneLike(movieId, userId);

            if (!like) {
                await this.likeRepository.createLike(movieId, userId);
                await this.likeRepository.incrementMovieLike(movieId);
                await queryRunner.commitTransaction();
                return '해당 영화에 좋아요를 등록하였습니다.';
            } else {
                await this.likeRepository.destroyLike(movieId, userId);
                await this.likeRepository.decrementMovieLike(movieId);
                await queryRunner.commitTransaction();
                return '해당 영화에 좋아요를 취소하였습니다.';
            }

        } catch (error) {
            await queryRunner.rollbackTransaction();
            throw new BadRequestException('영화 좋아요에 실패하였습니다.');
        } finally {
            await queryRunner.release();
        };
    }
}

 

 

 

참고

https://orkhan.gitbook.io/typeorm/docs/transactions

 

Transactions - typeorm

The following database drivers support the standard isolation levels (READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE):

orkhan.gitbook.io

https://velog.io/@chaerim1001/TypeORM-Transaction-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0

 

NestJS에서 TypeORM을 사용해 Transaction 처리하기 🎞

typeorm에서는 transaction을 어떻게 처리할까

velog.io

 

'Development > TIL' 카테고리의 다른 글

git stash(생성, 삭제, 복구)  (0) 2023.06.01
TypeORM Isolation Level  (0) 2023.05.30
NestJS_Configuration  (0) 2023.05.26
Nest.js (feat.Pipe)  (0) 2023.05.24
Nest.js(feat.DTO)  (0) 2023.05.22