트랜잭션은 요청을 처리하는 과정에서 데이터베이스에 변경이 일어나는 요청을 독립적으로 분리하고
에러가 발생했을 경우 이전 상태로 되돌리게 하기 위해 데이터베이스에서 제공하는 기능입니다.
QueryRunner
를 이용해서 단일 DB 커넥션 상태를 생성하고 관리하기transaction
객체를 생성해서 이용하기@Transaction
, @TransactionManager
, @TransactionRepository
데코레이터를 사용하기이중 데코레이터를 이용하는 방식은 Nest에서 권장하지 않는 방식이다.
결국 우린 QueryRunner
와 transaction
위주로 이용하면 됨.
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();
}
}
또 다른 방법으로 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
여기로 가면 자세히 볼 수 있음