TIL | 오늘의 에러 노트

bubblegum·2024년 3월 13일
0

Today I learn(TIL)

목록 보기
32/84
post-thumbnail
query: INSERT INTO `pointHistory`(`historyId`, `userId`, `reason`, `changedPoint`, `changedAt`) VALUES (DEFAULT, ?, ?, ?, DEFAULT) -- PARAMETERS: [4,"Refund",25200]

/Users/t2023-m0021/Documents/Project/online-ticket/src/driver/mysql/MysqlQueryRunner.ts:191
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
                                   ^
QueryRunnerAlreadyReleasedError: Query runner already released. Cannot run queries anymore.
    at MysqlQueryRunner.query (/Users/t2023-m0021/Documents/Project/online-ticket/src/driver/mysql/MysqlQueryRunner.ts:191:36)
    at SelectQueryBuilder.loadRawResults (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:3805:43)
    at SelectQueryBuilder.executeEntitiesAndRawResults (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:3551:37)
    at SelectQueryBuilder.getRawAndEntities (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:1670:40)
    at SelectQueryBuilder.getMany (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:1760:36)
    at ReturningResultsEntityUpdator.insert (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/ReturningResultsEntityUpdator.ts:247:18)
    at InsertQueryBuilder.execute (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/InsertQueryBuilder.ts:175:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at SubjectExecutor.executeInsertOperations (/Users/t2023-m0021/Documents/Project/online-ticket/src/persistence/SubjectExecutor.ts:435:42)
    at SubjectExecutor.execute (/Users/t2023-m0021/Documents/Project/online-ticket/src/persistence/SubjectExecutor.ts:137:9)

이 오류는 이미 해제된 쿼리 러너에서 추가 쿼리를 실행하려고 시도했기 때문에 발생한 것으로 보입니다. 쿼리 러너는 한 번 해제되면 더 이상 쿼리를 실행할 수 없습니다.

이러한 오류를 해결하기 위해서는 쿼리 러너가 이미 해제되었는지 확인하고, 그렇다면 더 이상 쿼리를 실행하지 않도록 처리해야 합니다. 따라서 쿼리 러너가 이미 해제되었는지 여부를 확인하여 오류를 방지하는 것이 좋습니다.

쿼리 러너가 이미 해제되었다면 해당 오류를 무시하고 추가 쿼리를 실행하지 않도록 처리해야 합니다. 이를 통해 오류를 방지하고 애플리케이션의 안정성을 유지할 수 있습니다.

문제의 코드

const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      // 환불하기 절차: 환불 금액 가져와서 히스토리에 포스팅 -> 예약 정보 삭제하기 -> 좌석에 아이디 빼주고 sale true로 변경
      const refund = queryRunner.manager.getRepository(PointHistory).save({
        userId: user.userId,
        changedPoint: penalty,
        reason: Reason.Refund, // 접근할 수 없는 코드
      });

      console.log('refund', refund);

      await queryRunner.manager.softDelete(Reservation, reservationId);

      await queryRunner.manager
        .getRepository(Reservation)
        .createQueryBuilder()
        .update()
        .set({ cancelledAt: today })
        .where('reservationId = :reservationId', {
          reservationId: reservationId,
        })
        .execute();
      console.log(foundTicket.reservedSeat);
      const seatArr = JSON.parse(foundTicket.reservedSeat);

      console.log('seatArr', seatArr);

      for (let i = 0; i < seatArr.length; i++) {
        await queryRunner.manager
          .getRepository(Seat)
          .update({ seatId: seatArr[i] }, { sale: true, userId: null });
      }

      return refund;
      await queryRunner.commitTransaction();
    } catch (error) {
      await queryRunner.rollbackTransaction();
    } finally {
      await queryRunner.release();
    }

return 문을 바로 밑에 있는 커밋 지점과 위치를 바꿔보니 해결됨.

query: START TRANSACTION
5
query: UPDATE `reservation` SET `cancelledAt` = CURRENT_TIMESTAMP WHERE `reservationId` IN (?) -- PARAMETERS: [5]
query: UPDATE `reservation` SET `cancelledAt` = ? WHERE `reservationId` = ? -- PARAMETERS: ["2024-03-13T18:08:32.048Z",5]
[3,4]
seatArr [ 3, 4 ]
query: UPDATE `seat` SET `sale` = ?, `userId` = ? WHERE `seatId` = ? -- PARAMETERS: [true,null,3]
query: UPDATE `seat` SET `sale` = ?, `userId` = ? WHERE `seatId` = ? -- PARAMETERS: [true,null,4]
업데이트가 잘못됨
Promise { <pending> }
query: COMMIT
query: INSERT INTO `pointHistory`(`historyId`, `userId`, `reason`, `changedPoint`, `changedAt`) VALUES (DEFAULT, ?, ?, ?, DEFAULT) -- PARAMETERS: [2,"Refund",25200]
[Nest] 37838  - 2024. 03. 14. 오전 3:08:32   ERROR [ExceptionsHandler] Query runner already released. Cannot run queries anymore.
QueryRunnerAlreadyReleasedError: Query runner already released. Cannot run queries anymore.
    at MysqlQueryRunner.query (/Users/t2023-m0021/Documents/Project/online-ticket/src/driver/mysql/MysqlQueryRunner.ts:191:36)
    at SelectQueryBuilder.loadRawResults (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:3805:43)
    at SelectQueryBuilder.executeEntitiesAndRawResults (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:3551:37)
    at SelectQueryBuilder.getRawAndEntities (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:1670:40)
    at SelectQueryBuilder.getMany (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/SelectQueryBuilder.ts:1760:36)
    at ReturningResultsEntityUpdator.insert (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/ReturningResultsEntityUpdator.ts:247:18)
    at InsertQueryBuilder.execute (/Users/t2023-m0021/Documents/Project/online-ticket/src/query-builder/InsertQueryBuilder.ts:175:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at SubjectExecutor.executeInsertOperations (/Users/t2023-m0021/Documents/Project/online-ticket/src/persistence/SubjectExecutor.ts:435:42)
    at SubjectExecutor.execute (/Users/t2023-m0021/Documents/Project/online-ticket/src/persistence/SubjectExecutor.ts:137:9)

이 로그에서는 다음과 같은 순서로 작업이 진행되었습니다:

트랜잭션 시작 (START TRANSACTION)
예약 취소에 대한 업데이트 쿼리 실행 (UPDATE reservation)
좌석 상태 업데이트 쿼리 실행 (UPDATE seat)
트랜잭션 커밋 (COMMIT)
포인트 히스토리 삽입 쿼리 실행 (INSERT INTO pointHistory)
그러나 마지막 단계에서 "QueryRunnerAlreadyReleasedError"가 발생했습니다. 이것은 이미 해제된 쿼리 러너에서 추가 쿼리를 실행하려고 시도했기 때문에 발생한 오류입니다.

문제의 코드

 const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      // 환불하기 절차: 환불 금액 가져와서 히스토리에 포스팅 -> 예약 정보 삭제하기 -> 좌석에 아이디 빼주고 sale true로 변경

      queryRunner.manager.softDelete(Reservation, reservationId);
      console.log(reservationId);

      await queryRunner.manager
        .getRepository(Reservation)
        .createQueryBuilder()
        .update()
        .set({ cancelledAt: today })
        .where('reservationId = :reservationId', {
          reservationId: reservationId,
        })
        .execute();
      console.log(foundTicket.reservedSeat);
      const seatArr = JSON.parse(foundTicket.reservedSeat);

      console.log('seatArr', seatArr);

      for (let i = 0; i < seatArr.length; i++) {
        await queryRunner.manager
          .getRepository(Seat)
          .update({ seatId: seatArr[i] }, { sale: true, userId: null });
      }
      console.log('업데이트가 잘못됨');
      const refund = queryRunner.manager.getRepository(PointHistory).save({
        userId: user.userId,
        changedPoint: penalty,
        reason: Reason.Refund,
      });
      console.log(refund);
      await queryRunner.commitTransaction();

      return refund;

콘솔에 Promise {}이 있는 걸로 봐서 await 문제로 보고 refund에 await를 넣어줌으써 문제를 해결하였다.

profile
황세민

0개의 댓글

관련 채용 정보