• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

Transactional 시 Exception 에 대하여

23.01.16 17:30 작성 조회수 2.02k

0

안녕하세요. 개인적인 질문을 좀 올려보게 되었습니다..

Service Logic 에서 Transactional 이 적용되어 persist를 하는 시점에 발생하는 에러에 대해서 문의드리고 싶습니다. 사실 JPA 쪽이 엮이긴 했지만 실전 강의에 올리는게 맞는 듯한 질문인데, 영속성 컨텍스트 쪽에 대한 고민이 커서 이쪽에 올려보게 되었습니다 ...

다음과 같은 로직이 있을경우,

@Transactional
public String processSignin(String uid, String email) {

    String uid = memberSigninDto.getUid();
    String email = memberSigninDto.getEmail();


    MemberInfo memberInfo = new MemberInfo(email);
    Member member = new Member(uid, memberInfo); // MEMBERINFO 는 Cascade.ALL 로 설정됨

    try {

        memberRepository.save(member);

    } catch (Exception e) {

        System.out.println("e.getClass() = " + e.getClass());
        e.printStackTrace();

    }

    return "Successful";

}

이와 같은 로직을 수행해보았습니다. uid 값에 한해서 Unique 제약 조건이 걸려 있는 상황이라, 만약에 같은 id 로 회원가입을 시도할 시 다음과 같이 Duplicate Entry 에러가 발생하게 됩니다.

o.h.engine.jdbc.spi.SqlExceptionHelper   : Duplicate entry '' for key 'member.UKhjme2qjwkdqp9lwmghidnpn6w'

JPA 관련 질문은 다음과 같습니다.

위와 같은 상황에서 Exception 을 잡지 못하는 이유는 영속성 컨텍스트에 Member 와 MemberInfo 가 저장되어 있는 상황에서 try catch 를 수행하고, return 까지 그냥 수행하기 때문인 것 같습니다. 즉 Transactional 걸린 로직이 끝나지 않았기 때문에 SQL이 커밋되지 않았고, 해당 함수가 끝나서야 에러가 발생하는 모습으로 보입니다.

이와 같은 상황에서 다음과 같은 해결책(?) 을 생각해보았습니다.

1) 해당 로직에 대한 Transactional 을 Repository 에 건다.
2) memberRepository 에 private final Entity Manager가 있기 때문에 해당 함수에서 flush, clear 하는 함수를 만든 다음에 memberRepository.flush() 를 수행해준다.


1), 2) 둘다 상황을 해결해주는 것 같긴 하지만, 뭔가 내키지 않는 방법들인 것 같은데, 이렇게 persist 만 하고 트랜젝션 로직이 끝나야 하는 상황에서는 SQL 단에서 발생하는 에러를 어떻게 캐치하는지 알 수 있을까요?

찾아보니 RollbackFor 에 대한 설명이 제일 많은데, 그건 그냥 해당 Exception 발생시 Rollback 을 하라고 하는 것이라, 응답을 처리해주기 위해서는 아닌 것 같았습니다.

개인적인 질문이지만.. 읽어주셔서 감사드립니다.

답변 1

답변을 작성해보세요.

0

안녕하세요. 강우석님

이 문제는 생각하신 것 처럼 결국 flush()를 직접 호출하거나 트랜잭션이 커밋 되어야 문제를 확인할 수 있다는 한계가 있습니다.

그래서 생각하신 것 처럼 1,2 둘중에 하나를 선택해서 처리해야 합니다.

감사합니다.