개발하는 자몽

[JPA Error] No EntityManager with actual transaction available for current thread - cannot reliably process 'flush' call 본문

Java/Spring

[JPA Error] No EntityManager with actual transaction available for current thread - cannot reliably process 'flush' call

jaamong 2024. 10. 23. 20:04

에러 원인

정말... 바보같은... 실수였다...

 

오류가 났던 테스트 코드는 아래와 같다.

	...
    
    @PersistenceContext
    EntityManager em;

    @Test
    void test() { 
        UserEntity userEntity = UserEntity.builder()
                .nickname("test")
                .email("test@example.com")
                .build();
        userEntity = userRepository.save(userEntity);
        userService.sumTotalAmount(userEntity, 10_000L);

        Long requestAmount = 5_000L;
        Long updatedAmount = userService.minusTotalAmount(userEntity, requestAmount);

        em.flush();
        em.clear();

        //잘 반영이 되었는지 확인하기 위해 영속성 컨텍스트를 비우고 새로 조회
        UserEntity findEntity = userRepository.findById(userEntity.getId()).get();

        assertThat(updatedAmount).isEqualTo(5_000L);
        assertThat(findEntity.getTotalAmount()).isEqualTo(updatedAmount);
    }

테스트 하고 싶었던 부분은 `minusTotalAmount`가 요청한 만큼 `totalAmount`를 잘 감소시키는 지였다. 

 

우선 `em.flush()`로 쿼리를 날려주고, 영속성 컨텍스트를 비운 상태에서 객체를 새로 조회하기 위해 `em.clear()`를 호출했었다. 그다음 객체를 새로 조회하여 필드에 제대로 값이 반영이 되었는지 검증했다.

 

그리고 제목과 같은 에러가 발생했다.

번역하자면...

현재 스레드에 사용 가능한 실제 트랜잭션이 있는 EntityManager가 없습니다. 'flush' 호출을 안정적으로 처리할 수 없습니다.

 

`EntityManager`가 `flush()`를 호출했는데 이를 처리할 Transaction이 없어서 실행할 수 없다는 뜻이다.

 

JPA는 트랜잭션 단위로 기능을 수행하고, 수행하면서 1차 캐시에 저장된 엔티티들은 DB에 flush되어 영속화된다. 그런데 위 테스트 코드는 트랜잭션이 없기 때문에 위와 같은 에러가 발생했던 것이다.

 

 

에러 해결

아주 간단히 해결할 수 있다... 테스트할 메서드나 클래스에 `@Transactional`를 붙여주면 된다! 

	...
    
    @PersistenceContext
    EntityManager em;

    @Test
    @Transactional
    void test() { 
        UserEntity userEntity = UserEntity.builder()
                .nickname("test")
                .email("test@example.com")
                .build();
        userEntity = userRepository.save(userEntity);
        userService.sumTotalAmount(userEntity, 10_000L);

        Long requestAmount = 5_000L;
        Long updatedAmount = userService.minusTotalAmount(userEntity, requestAmount);

        em.flush();
        em.clear();

        //잘 반영이 되었는지 확인하기 위해 영속성 컨텍스트를 비우고 새로 조회
        UserEntity findEntity = userRepository.findById(userEntity.getId()).get();

        assertThat(updatedAmount).isEqualTo(5_000L);
        assertThat(findEntity.getTotalAmount()).isEqualTo(updatedAmount);
    }

이제 `flush()`를 호출하고 콘솔창을 확인하면 쿼리가 제대로 나가는 것을 확인할 수 있다^^!

 

 

 

Comments