HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
Spring Data
Spring Data
/
🧣
JPA(Java Persistence API)
/
📷
Converter
📷

Converter

Converter(Entity ↔ db 값 변환)@Converter(autoApply=true)Converter 사용 시 주의할 점

Converter(Entity ↔ db 값 변환)

  • 위와 같이 @Converter와 @Convert를 통하여 데이터베이스에 저장된 특정 값을 객체로 매핑해서 활용할 수 있음
  • 이 때, database column에 생성되는 field의 type은 AttributeConverter의 두번째 generic type을 따라서 생성됨

@Converter(autoApply=true)

  • AttributeConverter의 첫번째 generic type에 선언된 클래스를 필드로 가지고 있는 Entity에 대해 자동으로 Converter를 적용해주는 옵션임
  • BookStatus와 같이 사용자가 만든 객체면 autoApply 사용해도 괜찮지만, String, Integer와 같은 일반적인 클래스를 변환할 때는 autoApply 적용 안하는 것이 좋음

Converter 사용 시 주의할 점

  • 만약에 legacy 데이터여서 읽기만 하고 쓰기 상황은 없다고 생각하고 Converter의 convertoDatabaseColumn() 메서드를 구현하지 않았을 때 생기는 문제
  • getAll() 메써드를 @Transactional을 적용함으로써, 끝날 때, dirty checking을 하게 됨
  • Entity를 db 값을 변환했을 때 Transaction의 처음과 동일하지 않으면 update를 하게 되는데 converToDatabaseColumn() 이 null을 반환하기에 값이 달라졌음 → update 쿼리를 하게 됨
  • 즉, 조회만 두번 했는데 dirty checking으로 인해 update 쿼리가 발생함으로 데이터가 null로 바뀌게 됨
  • 여기서 알게 된것 ! ⇒ dirty checking 시, entity의 값을 db field값으로 변환한 뒤에 비교하고 update를 날림! convertToDatabaseColumn() 이 잘 구현되어 있으면 update 쿼리 안생김
// Book.java public class Book{ @Convert(converter=BookStatusConverter.class) private BookStatus status; } //BookStatus.java @Data public class BookStatus { private long code; private String description; public boolean isDisplayed(){ return code == 200; } public BookStatus(long code){ this.code = code; this.description = parseDescription(code); } public String parseDescription(long code){ switch((int) code){ case 100: return "판매종료"; case 200: return "판매중"; case 300: return "판매보류"; default: return "미지원"; } } } // BookStatusConverter.java @Converter // jpa에서 사용하는 converter (autoApply = true) 가 적용되면 // BookStatus가 선언된 필드는 다 적용해줌 public class BookStatusConverter implements AttributeConverter<BookStatus, Long> { @Override public Long convertToDatabaseColumn(BookStatus attribute) { return attribute.getCode(); } @Override public BookStatus convertToEntityAttribute(Long dbData) { return dbData != null? new BookStatus(dbData) : null; } }
public class BookStatusConverter implements AttributeConverter<BookStatus, Long> { @Override public Long convertToDatabaseColumn(BookStatus attribute) { // return attribute.getCode(); return null; } @Override public BookStatus convertToEntityAttribute(Long dbData) { return dbData != null? new BookStatus(dbData) : null; } } @Transactional public List<Book> getAll(){ List<Book> books = bookRepository.findAll(); books.forEach(System.out::println); return books; } @Test void converterErrorTest(){ bookService.getAll(); bookRepository.findAll().forEach(System.out::println); }