포스트

2021-04-23-TIL

2021-04-23-TIL

Spring Data JDBC

Spring Data JDBC를 적용하면서 모은 자료다. 주제별로 묶어 정리한다.


JPA와 무엇이 다른가

Spring 블로그의 소개 글에 따르면 Spring Data JDBC는 JPA의 세 가지 기능을 일부러 빼 버렸다. 지연 로딩은 예상하지 못한 시점에 비싼 쿼리를 보내거나 예외를 낼 수 있고, 캐시는 엔티티의 두 버전을 비교하고 싶을 때 방해가 되며, 변경 감지(dirty tracking)는 모든 영속성 작업이 지나가는 한 지점을 찾기 어렵게 만든다는 이유다. 대신 SQL은 리포지토리 메서드를 호출할 때만 실행되고, 메서드가 반환한 객체는 이미 완전히 로딩된 상태다. 세션이나 프록시가 없어서 동작을 예측하기 쉽다는 것이 설계 목표다.


애그리거트와 참조

두 번째 블로그 글은 애그리거트(aggregate) 규칙을 설명한다. 애그리거트 루트에서 참조를 따라 닿을 수 있는 모든 것은 그 애그리거트에 속하고, 함께 저장되고 함께 삭제된다. 여러 애그리거트가 같은 엔티티를 참조한다면 그 엔티티는 어느 애그리거트에도 속할 수 없다. 그래서 다대일, 다대다 관계는 객체 참조가 아니라 ID만으로 모델링해야 한다고 정리한다.

flowchart LR
    subgraph A["주문 애그리거트"]
        O["PurchaseOrder (루트)"] --> I1["OrderItem"]
        O --> I2["OrderItem"]
    end
    subgraph B["회원 애그리거트"]
        M["Member (루트)"]
    end
    O -. "memberId만 보관" .-> M

ID 참조는 애그리거트 경계를 분명히 하고 도메인 모델 수준에서 결합을 끊는다. 일대다와 다대일 관계 자체의 차이는 Stack Overflow 답변이 테이블 관점에서 정리한다.


ID와 insert/update 판단

Spring Data JDBC는 save()를 호출했을 때 엔티티가 새것인지를 보고 INSERT와 UPDATE를 고른다. 기본 규칙은 ID 필드가 null(원시 타입이면 0)이면 새 엔티티로 본다. 그래서 ID를 애플리케이션에서 직접 채워 넣는 경우에는 Persistable을 구현하거나 버전 필드를 두어 새 엔티티임을 알려 줘야 한다. “Id 삽입 전략” 글이 이 문제를 다룬다.

  • https://velog.io/@bread_dd/Spring-Data-JDBC-vs-Spring-Data-JPA
  • https://hackmd.io/@ddubson/rkn-sR4wU
  • https://spring.io/blog/2018/09/17/introducing-spring-data-jdbc
  • https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates
  • https://www.docs4dev.com/docs/en/spring-data-jdbc/1.0.5.RELEASE/reference/all.html#reference
  • https://ordina-jworks.github.io/java/2020/01/02/Spring-Data-Jdbc.html
  • https://docs.spring.io/spring-data/jdbc/docs/1.1.0.RC2/reference/html/#reference
  • https://docs.spring.io/spring-data/jdbc/docs/1.0.0.RC1/reference/html/
  • https://javabydeveloper.com/spring-data-jdbc-2-0-with-spring-boot-example/
  • https://stackoverflow.com/tags/spring-data-jdbc/hot?filter=year
  • https://spring.io/blog/2018/09/17/introducing-spring-data-jdbc
  • https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates
  • https://stackoverflow.com/questions/3113885/difference-between-one-to-many-many-to-one-and-many-to-many#:~:text=In%20a%20One%2DTo%2DMany,in%20the%20larger%20application%20context).
  • https://skyblue300a.tistory.com/9

JdbcTemplate

Spring Data JDBC의 리포지토리로 표현하기 어려운 쿼리는 JdbcTemplate으로 직접 작성한다. JdbcTemplate은 커넥션 획득과 반납, 예외 변환 같은 반복 코드를 대신 처리하고, 개발자는 SQL과 결과를 객체로 바꾸는 RowMapper만 작성한다.

  • https://www.baeldung.com/spring-jdbc-jdbctemplate

DB 초기화

Spring Boot는 클래스패스 루트의 schema.sql(DDL)과 data.sql(초기 데이터)을 애플리케이션 시작 시 실행할 수 있다. Boot 2.0 문서 기준으로 내장 DB(H2 등)에서는 기본으로 실행되고, MySQL 같은 외부 DB에서는 spring.datasource.initialization-mode=always를 설정해야 실행된다.

  • https://docs.spring.io/spring-boot/docs/2.0.0.M6/reference/html/howto-database-initialization.html
  • https://pravusid.kr/java/2018/10/10/spring-database-initialization.html

엔티티와 DTO 변환

엔티티를 그대로 응답으로 내보내지 않고 DTO로 바꿔서 내보내는 이유와 방법, 그리고 변환 코드를 줄여 주는 ModelMapper 사용법을 다룬 글이다.

  • https://dbbymoon.tistory.com/4

JSON 필드 여러 개를 하나의 Java 필드로

요청 JSON에서 같은 의미의 값이 다른 키 이름으로 들어올 때, Jackson의 @JsonAlias({"name", "title"})를 쓰면 역직렬화 시 여러 이름을 한 필드로 받을 수 있다. 직렬화할 때는 원래 필드 이름(또는 @JsonProperty)만 쓴다.

  • https://www.baeldung.com/json-multiple-fields-single-java-field

Stream을 Set으로

stream.collect(Collectors.toSet())으로 모은다. 구현체가 정해져 있지 않으므로 특정 Set이 필요하면 Collectors.toCollection(TreeSet::new)를 쓴다.

  • https://www.geeksforgeeks.org/convert-stream-set-java/

MySQL 설정

MySQL 설정 관련 글이다. 그중 두 번째 글은 AWS에 띄운 MySQL에 외부에서 접속하도록 허용하는 방법을 다룬다. MySQL 사용자의 접속 허용 호스트와 bind-address 설정, 그리고 보안 그룹의 3306 포트 인바운드 규칙을 함께 열어야 접속된다.

  • https://nickjoit.tistory.com/144
  • https://emong.tistory.com/235

API Document tools

mockapi.io는 엔드포인트와 응답 데이터를 정의하면 가짜 REST API를 만들어 주는 서비스다. 백엔드가 완성되기 전에 프론트엔드가 API 형식에 맞춰 먼저 개발할 수 있다.

  • https://mockapi.io/projects
참고한 자료외부 출처 4

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다