
ParsingMenu 클래스의 saveEblockMenu() 메서드에 있는deleteAllByRestaurantPropertyId() 메서드가 해당 에러로 작동하지 않았다.

해당 메서드는 JPA 커스텀 메서드다.
분명히saveEblockMenu()에 @Transactional 을 선언했는데 동작하지 않는다.. 왜 이럴까?
답은 @Transactional의 동작 원리에 있었다.
위의 saveEblockMenu() 메서드는 (1)getDataAndSaveToDatabase() -> (2)getDataAndSaveToDatabaseEblock() -> (3)saveEblockFileName() -> (4)saveEblockMenu() 순으로 호출된다.
근데 나는 맨 처음 호출하는 메서드인 (1)getDataAndSaveToDatabase() 에 @Transactional를 추가하지 않았다.
호출하는 메서드에 @Transactional이 적용되어 있지 않으니까 당연히 하위 메서드들도 적용(전파)되지 않는다.
따라서 (1)getDataAndSaveToDatabase()메서드를 트랜잭션으로 감싸주는 프록시 객체가 만들어지지 않고, EntityManager가 존재하지 않는다는 에러가 난 것이다.
그런데 이상하다. 중간에 (3)saveEblockFileName()에서도 JPA의 save를 사용하는데 에러가 나지 않고 왜 (4)saveEblockMenu()의 delete에서만 에러가 날까?

해당 메서드 내용이다. 여기서도 EntityManager가 필요한 save를 사용하고 있다. 그러나 이 부분에서는 에러가 나지 않는다.
한 번 JpaRepository의 defalut 구현체인 SimpleJpaRepository를 살펴보자.

@Transactional이 붙어있다. 따라서 에러가 나지 않았던 것이다.
이것이 무슨 소리냐 하면..
나는
(1)getDataAndSaveToDatabase() -> (2)getDataAndSaveToDatabaseEblock() -> (3)saveEblockFileName() -> (4)saveEblockMenu() 순으로 메서드를 호출했다.
그렇다면 내가 호출한 메서드는ParsingMenu::getDataAndSaveToDatabase()이며 이 메서드는 트랜잭션으로 감싸져 있지 않다. 따라서 영속성 컨텍스트가 필요한 작업이 있으면 에러가 날 것이다.
하지만 (3)saveEblockFileName()에서는 영속성 컨텍스트가 필요한 작업인 save를 사용해도 에러가 나지 않았다. 그 이유는 (3)saveEblockFileName()에서 JpaRepository::save()를 호출했기 때문이다.
주의할 점은 ParsingMenu의 메서드를 호출한게 아니다. JpaRepository 구현체의 save()메서드를 호출했다. 그리고 이 메서드는 @Transactional이 적용되어 있다. 따라서 트랜잭션으로 감싸진 프록시 객체를 사용할 것이다. 당연히 에러가 나지 않는다.
그런데 (4)saveEblockMenu()의 deleteAllByRestaurantPropertyId()는 내가 만든 커스텀 메서드다. 이 메서드는 나중에 동적 프록시에 의해 분석되어 구현되고 JpaRepository::deleteAllByRestaurantPropertyId()로 실행된다. 하지만 중요한건 이 메서드엔 @Transactional이 자동으로 적용되지 않는다는 점이다.
따라서 해당 메서드에 @Transactional을 적용시키면 (1)getDataAndSaveToDatabase()에 @Transactional을 적용시키지 않아도 해결된다.

내 상황에서는 해결 방법이 세 가지가 있을 것 같다.
@Transactional를 적용시켜 전파시킨다.@Transactional를 적용시킨다.나는 3번을 택했다.
트렌젝션을 적용하지 않아도 잘 작동하는 기본 메서드에 대해 의문을 갖고 있었는데 정말 감사합니다.