• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

트랜잭션 질문드립니다!

21.07.06 11:08 작성 조회수 839

4

안녕하세요.

지난 번에 @TransactionRepository 데코레이터를 이용하여 두 가지 방법으로 트랜잭션을 구현했으나, 뜻대로 잘 동작하지 않는 것 같아서 질문을 드렸었습니다.

그래서 이번에는 아래와 같은 조건으로 다시 구현해봤습니다.

1. 트랜잭션을 디테일하게 컨트롤할 수 있는 Connection/QueryRunner 사용

(공식문서에서는 데코레이터를 이용한 트랜잭션을 권장하지 않는다고 기재)

2. Custom Repository를 만들어, 직접 쿼리 수행하는 로직을 분리(?)

위와 같이 구현함으로써 트랜잭션 동작이 정상적으로 동작하는 것을 확인할 수 있었고, 트랜잭션의 범위도 디테일하게 조정할 수 있다는 것도 확인할 수 있었습니다.

그런데, 위와 같은 방식으로 구현하는 것이 과연 좋은 방법일까?라는 의문이 들었습니다. 서비스 계층에서의 코드가 더욱 복잡해지는 거 같고, 특히 커스텀 레포지터리를 메소드 내부에서 불러오는게 옳은 건지도 잘 모르겠습니다ㅠㅜ 이로 인해 나중에 테스트코드 작성이 어려워지는 건 아닐까 싶고...

제로초님의 의견이 궁금하기도 하고, 조언도 부탁드리겠습니다!

답변 6

·

답변을 작성해보세요.

4

몇 달 더 써본 결과 공식문서에서처럼 @Transaction, @TransactionRepository를 쓰지 않고 queryRunner를 쓰는게 제일 좋습니다. 데코레이터로는 제대로 돌아가지 않는 경우도 많고, 테스팅하기도 힘들더라고요.

3

저도 저런 식으로 많이 하긴 합니다. 다만 try catch로 감싸는 것 때문에 가끔씩 throw Exception하는게 삼켜져서 실수도 많이 하고 있습니다. 

https://github.com/odavid/typeorm-transactional-cls-hooked

이런 라이브러리도 있긴 한데, 결국 디테일하게 컨트롤하려면 queryRunner나 transactionEntityManager가 필요한 것 같습니다.

1

Incursio님의 프로필

Incursio

2021.07.07

두 분 모두 친절한 답변 감사드립니다ㅎㅎ 공부가 만힝 됐습니다.

0

moretall님의 프로필

moretall

2021.08.27

감사합니다 잘봤습니다!

0

서준석님의 프로필

서준석

질문자

2021.07.06

제로초님 말씀의 의미는 아래와 같다고 보면 될까요?

위와 같은 방법으로도 시도를 해봤는데, 다음과 같은 에러가 발생합니다.

타입과 관련된 문제인거 같은데.. 막상 서버를 돌려놓고 요청을 보내보면 정상적으로 쿼리를 수행하긴 하네요!!

아뇨 getCustomRepo 없이 일반 레포쓰듯 해도 되더라고요

서준석님의 프로필

서준석

질문자

2021.07.06

그럼 아래와 같은 방식을 말씀하신걸까요?

말씀하신대로 queryRunner을 사용하면서, 의존성 주입을 통해 가져온 레포지토리(this.xxx)를 사용하면 다음과 같이 트랜잭션이 두 개 열리는 것을 볼 수 있었습니다.

또한 실제 커넥션 사용 정보를 봐도 동시에 두 개의 커넥션이 사용됐다는 것을 확인해볼 수 있었습니다.

의존성 주입으로 가져온 커스텀 레포지토리(this.xxx)를 그냥 이용하면 아마 queryRunner로 열어놓은 커넥션을 이용하지 않는 것 같습니다..!

결국 connection(queryBuilder)으로 설정하는 트랜잭션커스텀 레포지토리를 사용하고자 한다면

getCustomRepository() 메소드로 직접 해당 레포지토리를 불러와야하는게 아닌가 싶습니다ㅠ

(TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.)

save할 때 transaction 끄시면 한번만 되는 것 아닌가요?

서준석님의 프로필

서준석

질문자

2021.07.07

위와 같은 상황에서는 save 메소드의 트랜잭션 옵션을 false로 설정해서 꺼놓는다고 해도 DB Connection을 두 개 사용하지 않을까요??

이따가 테스트를 한 번 해봐야겠네요!

서준석님의 프로필

서준석

질문자

2021.07.07

말씀하신대로 각 레포지토리의 save 메소드에 모두 {transaction: false} 옵션을 추가해서 요청을 보내봤습니다.

이번에는 트랜잭션이 한 번 실행된 것을 볼 수 있었습니다.

이는 qureyRunner로 가져온 connection에 의한 트랜잭션인 것 같습니다.

그러나 실제 DB에서 확인해보면 2개의 커넥션이 사용된 것을 확인할 수 있었습니다.

결론적으로 의존성 주입으로 가져온 레포지토리를 그대로 사용하면(getCustomRepository 메소드 없이),

queryRunner로 설정한 트랜잭션 범주에 포함되지 않는 것 같습니다. (서로 다른 커넥션을 사용하는 것으로 추측)

0

Incursio님의 프로필

Incursio

2021.07.06

혹시 작성자님 코드에서 getCustomRepository()할 때에 Repository를 의존성 주입을 하지 않고 바로 넣으셨는데, 의존성 주입을 하지 않아도 되는건가요? 궁금해서 여쭤봅니다.

this로 가져오는 것만 의존성주입하는 겁니다.

서준석님의 프로필

서준석

질문자

2021.07.06

의존성 주입을 하지 않아도 된다기 보다는..

저도 DI를 통해 레포지토리를 갖고와서 사용하고 싶었는데,

queryRunner를 이용하여 트랜잭션을 구현하려고 하다보니

getCustomRepository() 메소드로 사용할 레포지토리를 직접 가져오게 됐습니다.

이렇게도 해보고 저렇게도 해보았으나, 위 방식으로 했을 때 원하는 대로 잘 동작하더라구요 ..

아직 미숙하다보니 해당 방법이 옳은지도 모르겠습니다 ㅠㅜ

이와 관련해서 더욱 공부해야 할 것 같습니다!

서준석님의 프로필

서준석

질문자

2021.07.06

위 방식대로 queryRunner를 사용하면서, 의존성 주입된 레포지토리를 사용하고 싶다면

queryRunner.manger를 해당 레포지토리에 매개변수로 넘겨주는 방법도 있는 것 같습니다.

참고: TypeORM의 Transaction 사용하기 (cherrypick.co.kr)

queryRunner 쓰면서 동시에 그냥 this.레포지토리 해도 정상 작동하지 않나요?