Typeorm Transaction

BackEnd_Ash.log·2022년 2월 24일
0

nestjs

목록 보기
7/12

✅ 트랜잭션 적용

트랜잭션은 요청을 처리하는 과정에서 데이터베이스에 변경이 일어나는 요청을 독립적으로 분리하고
에러가 발생했을 경우 이전 상태로 되돌리게 하기 위해 데이터베이스에서 제공하는 기능입니다.

📌 근데 이거 왜써 ??

  • 데이터의 일관성을 유지하면서 안정적으로 데이터를 복구하기 위함
  • 데이터베이스에서 처리하는 도중 오류가 발생하면 모든 작업을 원상태로 되돌릴려고
  • 처리 하는 과정 모두 성공 했을때만 최종적으로 데이터베이스에 반영함

📌 방식 3가지

  • QueryRunner 를 이용해서 단일 DB 커넥션 상태를 생성하고 관리하기
  • transaction 객체를 생성해서 이용하기
  • @Transaction, @TransactionManager, @TransactionRepository 데코레이터를 사용하기

이중 데코레이터를 이용하는 방식은 Nest에서 권장하지 않는 방식이다.

결국 우린 QueryRunnertransaction 위주로 이용하면 됨.

📌 어떻게 쓰는데 ?

QueryRunner 클래스를 사용하는 방법

QueryRunner 클래스를 사용하는 방법
QueryRunner를 이용하면 트랜잭션을 완전히 제어할 수 있습니다.

...
import { Connection, ... } from 'typeorm';

@Injectable()
export class UsersService {
  constructor(
        ...
        private connection: Connection, // 주입 
  ) { }
    ...
}

L8: 먼저 typeorm에 제공하는 Connection 객체를 주입해야한다고 함

private async saveUserUsingQueryRunner(name: string, email: string, password: string, signupVerifyToken: string) {
  const queryRunner = this.connection.createQueryRunner();

  await queryRunner.connect(); // 주입받은 Connection 객체에서 QueryRunner를 생성합니다.
  await queryRunner.startTransaction(); // QueryRunner에서 DB에 연결 후 트랜잭션을 시작합니다.

  try {
    const user = new UserEntity();
    user.id = ulid();
    user.name = name;
    user.email = email;
    user.password = password;
    user.signupVerifyToken = signupVerifyToken;

    await queryRunner.manager.save(user);

    // throw new InternalServerErrorException(); // 일부러 에러를 발생시켜 본다

    await queryRunner.commitTransaction();
    // DB 작업을 수행한 후 커밋을 해서 영속화를 완료합니다.
  } catch (e) {
    // 에러가 발생하면 롤백
    await queryRunner.rollbackTransaction();
  } finally {
    // 직접 생성한 QueryRunner는 해제시켜 주어야 함
    // finally구문을 통해 생성한 QueryRunner 객체를 해제합니다. 생성한 QueryRunner는 해제시켜 주어야 합니다
    await queryRunner.release();
  }
}

transaction 객체를 생성해서 이용하는 방법

또 다른 방법으로 connection 객체내의 transaction 메서드를 바로 이용하는 방법
이 메서드의 주석을 보겠습니다.

/**
 * Wraps given function execution (and all operations made there) into a transaction.
 * All database operations must be executed using provided entity manager.
 */
transaction<T>(runInTransaction: (entityManager: EntityManager) => Promise<T>): Promise<T>;

(transaction 메소스는) 주어진 함수 실행을 트랜잭션으로 래핑합니다.
모든 데이터베이스 연산은 제공된 엔티티 매니저를 이용하여 실행해야 합니다.

라는 뜻이다.

transaction 메소드는 EntityManager 를 콜백으로 받아 사용자가 어떤 작업을 수행할 함수를 작성할 수 있도록 해 줍니다.

private async saveUserUsingTransaction(name: string, email: string, password: string, signupVerifyToken: string) {
  await this.connection.transaction(async manager => {
    const user = new UserEntity();
    user.id = ulid();
    user.name = name;
    user.email = email;
    user.password = password;
    user.signupVerifyToken = signupVerifyToken;

    await manager.save(user);

    // throw new InternalServerErrorException();
  })
}

작성한거 사실
https://wikidocs.net/158616
여기로 가면 자세히 볼 수 있음

profile
꾸준함이란 ... ?

0개의 댓글