TypeORM Transaction에서 Repository 사용하기
transaction 구성중 Entity가 아닌 Repository 사용시
typeORM에서 transaction을 사용하는 방법은 몇가지가 있지만,
복잡한 service단의 처리에서는 아래의 queryRunner 방식이 더 적합할것 같아서
dataSource.createQueryRunner()
방식을 사용했다.1
|
|
문제 - commit 중복으로 rollbackTransaction 실패
FeedRepository
는 이미 그 자체로 코드 실행시 transaction이 따로이 실행된다.
즉, 여기서 이미 commit이 이루어진다는 뜻!
따라서 rollbackTransaction
을 하는데 있어 FeedRepository.createFeed
코드는 이미 commit
이 되었기에 rollback 해당 대상에서 벗어나게 된다.
위와 같이 FeedRepository
에서 START TRANSACTION
이 따로이 한번 더 일어나고,
아직 실행중이지만 도중에 COMMIT이 되어버림을 확인할 수 있다.
해결 - withRepository
메소드
고민을 해보자!
- transaction의 dataSource.manager는 따로 동작한다.
- 즉, 곰곰히 생각해보면
FeedRepository
단독실행이 아닌 아닌 저 transaction단에서 동작하는 범주 안에서 코딩이 이루어져야 한다. - 2가지 방안이 떠올랐다. 첫번째는
FeedRepository
안에 만들어놓은 메소드를 포기하고 따로이 다시금 transaction의 try문단 안에 코딩을 하는 것이고, 다른 하나는 저FeedRepository
를 어떻게든 transaction 동작 범주 안으로 우겨넣는 방법일 것이다.
다시금 코딩을 하자니 상당히 비효율적이고, 이건 도저히 아니라는 판단이 들었다.
그럼 우겨넣는 방법인데…
구글링을 해봐도 typeORM의 버전 업그레이드로 관련문서의 수도 적었고, 있다하더라도 대개 nestJS의 customRepository 관련 문서였다.
최후의 수단으로 IDE에서 사용가능한 메소드를 쭉 하나하나 살펴봤다.
그러다가 찾은 메소드 withRepository
지정된 리포지토리에서 새 리포지토리 인스턴스를 생성하고 현재 EntityManager 인스턴스를 해당 리포지토리로 설정합니다. 트랜잭션에서 사용자 지정 리포지토리로 작업하는 데 사용됩니다.
아~주 적절하다!
이렇게까지 복잡했던 이유는, 만약 해당 코드가 단순히 기본 Entity라면
|
|
간단하게 뭐 이렇게 나가면 된다.
하지만 단순한 Entity가 아닌, 이미 일련의 실행과정을 코딩해놓은 Repository이기에 아래와 같이
withRepository
메소드를 사용한다.
그러면 해당 레포에서 static으로 박아놓은 .createFeed
라는 하위 메소드도 연결해서 사용가능하다.
|
|
테스트 결과
이제 정상적으로 START TRANSACTION이 한번 일어나고,
의도적인 에러를 터트려 롤백하게 했더니 마지막으로 무사히 ROLLBACK이 이루어진다.
transaction안에 AWS S3 objectCommand까지 있어 코드가 좀 어지러웠지만 그래도 예상되는 모든 Transaction-Rollback 테스트가 모두 통과되어 되어 한시름 놓았다.
-
getConnection() 방식은 typeORM 0.3.x에서 deprecated 되었고, dataSource 방식으로 대체하면 된다. ↩︎
Related Content
- MySQL에서 이메일 재사용 가능하게 하기- Soft Delete와 Unique를 함께 활용하다.
- Node.js와 TypeORM에서 겪은 트랜잭션 롤백 문제 - 원인 분석과 해결 방법
- Error Log - TypeORM Migration 할 때 Cross ENV 설정 문제
- Node.js 백엔드TypeScript + TypeORM으로 무한 대댓글 가공하기
- TypeORM 시간대 설정에 관한 고찰 - TypeORM의 DateStrings와 Timezone 옵션에 따른 시간대 혼란