문제상황

서비스에 멤버필드를 넣었고 해당 필드를 immutable 하게 만들기위해 final로 선언했고, @value로 값을 주입했다.

아래 그림처럼->

아래그림처럼 바로 "String이라는 빈이 없는데?" 라며 에러가 터져버린다.

음... @RequiredArgsConstructor를 통해서 생성자를 만들때 final이 잘 초기화 될거라 생각했는데.. 갑자기 String을 빈으로 인식해버리네..?

 

그럼 직접 생성자를 만들어서, 초기화를 시켜주는 방법을 고안해보았다. 먼저 아래그림처럼 생성자를 만들었다. 

생성자만 만들면 @RequiredArgsConstructor 때와 동일하게 String을 빈으로 인식해서 빈객체로 만들려한다.

 

그럼 결론적으로 빈이 아닌 멤버필드를 @value를 사용해서 immutable 하게  어떻게 쓸수있을까!?

아래그림처럼 선언하면 가능해진다.

정리

1. @RequiredArgsConstructor 는 생성자 파라미터가 무조건 빈이라고 보기때문에 생성자를 통해 객체를 만들때 에러가 나는거라 유추된다.

2. 직접 생성자를 만들어서 생성자를 통해 객체를 만들때 @Value를 통하여 이 파라미터가 빈이 아니라는걸 명시 가능!

두개의 entity(ordergood, order_refund_detail)가 oneToMany 관계로 걸려있었다. 

엔드포인트를 테스트 코드에서 똑같이 재구현해서 테스트를 해봤는데, layzyInitialLazyInitializationException 이 발생을했다.

테스트 코드는 아래 그림과 같다.

 

원인은!

테스트코드는 시작시 영속성컨텍스트 안만들어준다..
지금의 스프링 OSIV에서는 필터단 부터 영속성컨텍스트가 시작되기때문에 그 하위 메소드들은 영속성 컨텍스트가 유지된다.
테스트코드에서는 필터,인터셉터를 지나치지 않았기때문에 영속성 컨텍스트를 안만들어 주는것이다. 후 삽질..


아래그림과같이 @Transactional을 테스트메소드에 추가해주면 해결 끝!



  • 문제상황
    • Controller -> Service -> Service(@Transactional) 
  • 문제이유
    • 컨트롤러에 디폴트로 Transaction이 걸려있다고 생각했다.(예전 osiv를 생각했던것임)
    • 그렇지만 현재의 스프링 osiv는 서비스단에 직접 트랜잭션을 명시해야 트랜잭션이 시작됨.
    • 최종적으로 호출되는 Service에는 @Transactional을 명시했는데? 왜 안된거지?
      • 같은 서비스 클래스 내에서의 호출(Service->Service(@Transactional)을 했기때문에 transaction이 전파? 되지않았다..
  • 문제해결
    • controller단에만 @transactional 명시
      • 예전 transaction 적용방법. 컨트롤러단에서 데이터를 변경하면 의도치않은 데이터 변경값이 뷰에 전달될가능성이 커서 안좋은 방법이다!! PASS!!
    • service단에 @transactional 명시
      • 외부에서 쓰일 메소드는 transactional 명시해놓음
      • 내부에서만 쓰일 메소드는 private로 명시함으로써 "이 메소드는 내부에서만 쓰일거고, 내부에서 호출은 transaction이 적용이 안돼!" 라는 것을 인지할수 있다. @Transactional 붙여보면 컴파일시점에서부터 에러가 남을 알수있음!

 

+ Recent posts