2022. 5. 31. 13:32ㆍERROR
에러 메시지
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual
transaction available for current thread - cannot reliably process 'persist' call
웹 개발중 테스트 데이터를 매 실행마다 입력하기 번거로워서
jpa:
hibernate:
ddl-auto: create
update로 변경할까 하다가, 그냥 애플리케이션이 실행할때마다 샘플 데이터를 저장하기로 했다.
일단 트랜잭션이 걸려있는 Service 단에서 sampleData 메소드를 작성했다.
빈 생성(여기서는 해당 코드가 있는 Service 클래스)과 의존관계 주입이 완료된 다음, sampleData 메소드가 실행되어
book 2개가 저장될거라고 기대했는데 맨 위의 오류코드를 맞닥뜨렸다.
현재 쓰레드에서 트랜잭션을 얻은 EntityManager가 없다는 뜻으로 해석된다.
구글링으로 도움을 얻은 링크를 첨부한다.
https://reflectoring.io/spring-boot-execute-on-startup/#postconstruct
The @PostConstruct method is called right after the bean has been created by Spring
A @PostConstruct method is inherently tied to a specific Spring bean so it should be used for the initialization logic of this single bean only.
In the @PostConstruct (as with the afterPropertiesSet from the InitializingBean interface) there is no way to ensure that all the post processing is already done, so (indeed) there can be no Transactions.
@PostConstruct 로 EntityManager를 사용 단일 Bean의 초기화 로직에만 사용해야 한다. @PostConstruct는 해당 빈만 생성되었다고 판단한 다음 호출되기 때문이다. 이는 곧, 해당 빈에 관련된 AOP 등을 포함하여, 전체 스프링 애플리케이션 컨텍스트가 초기화되었다는 것을 보장하지 않는다.
따라서 @PostConstruct 에서 사용가능한 트랜잭션이 없다는 말도 타당하다. 트랜잭션 AOP와 @PostConstruct의 적용 시점이 다르기 때문이다. AOP는 후 처리(post processing)가 완료되고 스프링의 애플리케이션 컨텍스트가 초기화 된 이후가 동작한다.
아래와 같은 해결방법을 찾았다.
https://sorjfkrh5078.tistory.com/311
- 다른 스프링 빈을 호출해서 사용하는 방법
- AOP를 사용하지 않고 트랜잭션을 직접 코딩하는 방법
- 애플리케이션 컨텍스트가 완전히 초기화된 이벤트를 받아서 호출하는 방법
- 초기화하는 메서드와 초기화를 실행하는 메서드를 분리하는 방법
세번째 방법으로 해결했다.
@EventListener(ApplicationReadyEvent.class)
위의 어노테이션을 추가한 것인데, 해당 메소드는 애플리케이션의 구동이 완료된 후에 실행된다. 찾고 있던 바로 그 기능이다.
아래는 출력한 로그다. @PostConstruct 로그와 ApplicationReadyEvent의 로그가 서로 다른 시점에 찍힌다.
마지막 방법 "초기화하는 메서드와 초기화를 실행하는 메서드를 분리하는 방법"은 아래의 블로그에서 확인할 수 있다.
https://velog.io/@hungry_foolish/Spring-PostConstruct%EC%97%90%EC%84%9C-transactional-%EC%B2%98%EB%A6%AC
Spring의 EventListener는 추후에 공부해야겠다.
'ERROR' 카테고리의 다른 글
JPA 에러: save the transient instance before flushing (0) | 2022.06.07 |
---|---|
No entity found for query 에러 (0) | 2022.06.01 |
Could not autowire. No beans of 'EntityManager' type found. (0) | 2022.05.30 |
Loading class 'com.mysql.jdbc.Driver'. This is deprecated. The new driver class is 'com.mysql.cj.jdbc.Driver'. (0) | 2022.05.18 |
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver (0) | 2022.05.18 |