[TroubleShooting (springboot)] No EntityManager with actual transaction available for current thread..

스프링부트에서 만난 오류다. 오류가 난 회원 레포지토리 코드는 아래와 같다.

@RunWith(SpringRunner.class) // junit에게 스프링관련테스트할것을 알림
@SpringBootTest
class MemberRepositoryTest {
    @Autowired MemberRepository memberRepository;

    @Test
    public void save() {
        // given
        Member member = new Member();
        member.setUsername("member1");

        // when
        Long savedId = memberRepository.save(member);
        Member findMember = memberRepository.findById(savedId);

        // then
        Assertions.assertThat(savedId).isEqualTo(findMember.getId());
        Assertions.assertThat(member.getUsername()).isEqualTo(findMember.getUsername());

    }
}

에러 확인

No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call

No EntityManager with actual transaction available for current thread

직역하면, 현재 스레드에서 사용가능한 실제 트랜잭션이 있는 엔티티매니저가 없다..

스프링 공부 잘 안하다 보니 '이게 뭔소리지??' 싶었다.

긴 호흡으로 이해해보기

먼저 용어

  • EntityManager는 엔티티 관리하는 클래스 인데, 매니저 내부에 영속성 컨텍스트를 두어 관리한다.

  • 영속성 컨텍스트 는 엔티티를 영구 저장하는 환경이다.

  • 트랜잭션 : 하나의 작업 단위로, 데이터 변경은 반드시 트랜잭션 안에서 이뤄진다.

  • flush : 영속성 컨텍스트의 변경 내용을 db에 반영, 트랜잭션이 일어날 때, flush가 동작한다.

이해 순서

  • 그래서 엔티티매니저가 어떻게 영속성 컨텍스트를 관리할까?
    트랜잭션이 정상 수행됐을 때, 커밋을 해서 실제 DB와 엔티티 매니저에 반영된다.

  • JPA에서의 모든 로직은 트랜잭션 안에서 수행해야 한다. 이건 왜 그럴까?
    트랜잭션 단위에 따라 1차 캐시 영역에 있는 객체들이 DB에 flush되어 영속화되기 때문이다.

  • 그래서 이 에러가 발생한 이유는??
    그러한 영속 작업을 하는 persist()메소드에 객체가 들어갔지만 가능한 transaction이 존재하지 않아서 발생한 에러다.

원인

EntityManager를 통한 모든 데이터 변경은 항상 transaction 안에서 이루어져야 하고, 테스트 메소드에 @Transactional을 선언하지 않았다.

해결

@Transactional을 선언한다.

@Test
@Transactional
public void save() {
...}

참고

좋은 웹페이지 즐겨찾기