nestjs typeorm transation

송인성·2021년 9월 19일
0

오늘은 nestjs에서 typeorm transaction을 어떻게 활용하는지에 대해서 보려고 합니다 🤔

typeorm에서는 transaction을 관리하는 내장 함수를 제공합니다.
일단 참고한 transaction docs를 공유합니다.
DOCS : https://orkhan.gitbook.io/typeorm/docs/transactions

typeorm을 통해서 transaction을 할 수 있는 방법은 여러개가 있는것으로 보여졌습니다.
그중에서도 가장 직관적이고 개발자가 수동적으로 작동시킬 수 있는 코드를 이용해서 코드화 작업을 해보았습니다.

import {getConnection} from "typeorm";

// get a connection and create a new query runner
const connection = getConnection();
const queryRunner = connection.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();
}

위의 코드는 docs에 나와있는 그대로의 코드입니다.
우선 각각의 연결이 어떻게 되는지를 우선적으로 보겠습니다.

const connection = getConnection();// typeorm을 통해서 db를 연결하는 코드입니다.
const queryRunner = connection.createQueryRunner(); //  새로운 쿼리 러너를 사용하겠다는 의미입니다.
await queryRunner.connect(); 
await queryRunner.startTransaction();
//쿼리 러너를 연결해서 transaction을 시작할 준비를 마쳤습니다.
@Injectable()
export class UsersService {
  private logger = new Logger('UsersService');

  constructor(
    @InjectRepository(Users)
    private readonly usersRepository: Repository<Users>,
    @InjectRepository(WorkspaceMembers)
    private readonly workspaceMembersRepository: Repository<WorkspaceMembers>,
    @InjectRepository(ChannelMembers)
    private readonly channelMembersRepository: Repository<ChannelMembers>,
    private readonly connection: Connection,
  ) {}

  async authorUser() {
    try {
    } catch (e) {
      console.log('authorUser Error: ', e);
    }
  }

  async join(joinData: JoinRequestDto): Promise<any> {
    const { email, nickname, password } = joinData;

    const user = await this.usersRepository.findOne({ where: { email } });
    console.log('user: ', user);
    if (user) {
      return new UnauthorizedException('이미 존재하는 사용자 입니다.');
    }

    const queryRunner = this.connection.createQueryRunner();
    try {
    
    //transation을 쓰지 않았다면 이러한 코드를 입력하면 됩니다.
    //그러나 transation을 하려면 아래와 같은 코드로 입력해선 안됩니다.
    //아래와 같이 입력하면 안되는 이유? 🤔
    //아래와 같은 연결은 typrorm.config에 연결되어있는 코드와 연결되는 코드입니다. 따라서 아래와 같은 코드를 입력하면 위에 transaction에서 연결한 코드로 연결되지 않아 transation에 원활하게 동작하지 않게됩니다. 따라서 아래와 같은 코드 대신해야합니다 (✅ 이모지에 따른 코드!)
    await this.workspaceMembersRepository.save({
    	UserId: returned.id,
        ChannelId: 1,
    })
    
    
    //✅ 여기와 같은 코드로 입력해야 transation의 진행이됩니다!
      await queryRunner.manager.getRepository(ChannelMembers).save({
        UserId: returned.id,
        ChannelId: 1,
      });

      await queryRunner.commitTransaction();
      return true;
    } catch (e) {
      this.logger.log('postUsers Error: ', e);
      await queryRunner.rollbackTransaction();
    } finally {
      //디비에는 최대 연결 계수가 있기떄문에 연결을 끊어주어야한다.
      await queryRunner.release();
    }
  }
}

profile
코드 한줄에 의미를 생각할 수 있는 개발자가 되어 가는중... 🧑🏻‍💻

0개의 댓글