Spring Data JDBC

박윤택·2022년 7월 21일
1

Spring

목록 보기
9/18

✨ JDBC(Java Database Connectivity)

Java 기반 애플리케이션에서의 코드 레벨에서 사용하는 데이터를 데이터베이스에 저장, 업데이트, 조회할 수 있도록 해주는 표준 API


JDBC 동작 흐름

  • JDBC 드라이버
    JDBC 드라이버는 데이터베이스와의 통신을 담당하는 인터페이스로 다양한 DB의 벤더에 맞는 JDBC 드라이버를 구현해서 제공을 하게 된다. 이 JDBC 구현체를 이용하여 특정 벤더의 DB에 엑세스 할 수 있다.

JDBC API 흐름

  1. JDBC 드라이버 로딩
    사용하고자 하는 JDBC 드라이버를 로딩, JDBC 드라이버는 DriverManager라는 클래스를 통해서 로딩된다.
  2. Connection 객체 생성
    JDBC 드라이버가 정상적으로 로딩되면 DriverManager를 통해 데이터베이스와 연결되는 세션(Session)인 Connection 객체를 생성한다.
  3. Statement 객체 생성
    Statement 객체는 작성된 SQL 쿼리문을 실행하기 위한 객체로써 객체 생성 후에 정적인 SQL 쿼리 문자열을 입력으로 가진다.
  4. Query 실행
    생성된 Statement 객체를 이용해서 입력한 SQL 쿼리를 실행
  5. ResultSet 객체로부터 데이터 조회
    실행된 SQL 쿼리문에 대한 결과 데이터 셋
  6. ResultSet 객체 Close, Statement 객체 Close, Connection 객체 Close
    JDBC API를 통해 사용된 객체들은 사용 이후에 사용한 순서의 역순으로 차례로 Close해준다.

🤔 Spring Data JDBC

Spring에서 사용할 수 있는 데이터 엑세스 기술 중 하나로 SQL 중심 기술이다.
JPA처럼 ORM(Object Relational Mapping) 기술을 사용하지만 JPA의 기술적 복합도를 낮춘 기술이다. 애플리케이션의 규모가 상대적으로 크지 않고, 복잡하지 않을 경우에 Spring Data JDBC가 뛰어난 생산성을 보여줄거라 기대하고 있다고 한다. 그리고 Spring Data Jpa와 달리 단방향 연관관계만 지원한다. 그리고 미리 작성된 DDL이 존재하여야 한다.

  • 의존성 라이브러리 추가
dependencies {
	...
	...
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
}
  • Repository 구현
@Repository
public interface UserRepository extens CrudRepository<User, Long> {
	...
}

CrudRepository 인터페이스를 상속받아 Repository를 구현한다.


🛒 DDD(Domain Driven Design)

DDD는 도메인 주도 설계로 도메인 위주의 설계 기법을 의미한다. 여기서 도메인이란 비즈니스적인 어떤 업무 영역과 관련이 있다.
예를 들어 주문 앱을 만든다면 주문과 관련된 기능에는 고객이 음식을 주문하는 과정, 주문하는 음식을 처리하는 과정, 조리된 음식을 배달하는 과정 등의 도메인 지식들을 서비스 계층에서 비즈니스 로직으로 구현해야 한다.


애그리거트(Aggregate)

업무 도메인의 묶음을 말한다.

배달앱의 경우 업무 도메인을 나눈다면 회원, 주문, 음식, 배달, 결제로 크게 나눌 수 있다. 이 각각의 요소들을 애그리거트라고 한다.


애그리거트 루트(Aggregate Root)

애그리거트를 좀 더 세부적으로 나눈다면 그 중 대표하는 도메인을 애그리거트 루트라고 한다.

  • 애그리거트 루트 선정 기준
    다른 도메인들과의 관계에서 연관이 주가 되는 도메인을 애그리거트 루트로 선정한다.
    데이터베이스의 테이블 간 관계로 본다면, 애그리거트 루트는 부모 테이블이 되고 애그리거트 루트가 아닌 다른 도메인들은 자식 테이블이 된다.
    애그리거트 루트의 기본키 정보들은 다른 도메인들의 외래키 형태로 가지게 된다.

📷 Spring Data JDBC에서의 연관관계

애그리거트 객체 매핑 규칙

1. 모든 엔티티 객체의 상태는 애그리거트 루트를 통해서만 변경할 수 있다.
2. 동일한 하나의 애그리거트 내에서는 엔티티 간에 객체로 참조한다.
3. 애그리거트 루트 간의 참조는 객체 참조 대신에 ID로 참조한다.

- 1대1과 1대N 관계일 때는 테이블 간의 외래키 방식과 동일
- N대N 관계일 때는 외래키 방식인 ID 참조와 객체 참조 방식이 함께 사용

-> 애그리거트 루트를 통해서 나머지 엔티티에 접근한다는 것은 어떤식으로든 애그리거트 루트가 나머지 모든 엔티티에 대한 객체를 직간접적으로 참조 할 수 있다는 의미


애그리거트 루트 간 매핑(1:N)

@Getter
@Setter
@NoArgsConstructor
public class Member {
	@Id
    private long memberId;
    
    ...
}


@Getter
@Setter
@NoArgsConstructor
@Table(name = "ORDERS")
public class Order {
	@Id
    private long orderId;
    
    private AggregateReference<Member, Long> memberId;
    
    ...
}

외래키가 존재해야 하는 곳에 AggregateReference를 넣어주고 참조할 객체와 아이디의 타입을 설정해준다.


애그리거트 루트 간 매핑(M:N)

다대다의 관계는 1:N:1로 분할한다.

@Getter
@Setter
@Table("ORDERS")
public class Order {
    @Id
    private long orderId;

    private AggregateReference<Member, Long> memberId;

    @MappedCollection(idColumn = "ORDER_ID")
    private Set<CoffeeRef> orderCoffees = new LinkedHashSet<>();
		
		...
		...
}

@Getter
@AllArgsConstructor
@Table("ORDER_FOOD") 
public class FoodRef {
    private long foodId; 
    private int quantity; 
}

주문 정보와 음식 주문 정보와의 연관 관계 매핑은 @MappedCollection(idColumn = "ORDER_ID")을 이용한다. 이는 애그리거트 루트와 애그리거트 간의 연관관계를 나타낼때 사용한다.


🎁 Spring Data JDBC를 통한 데이터 엑세스 계층 구현

public interface MemberRepository extends CrudRepository<Member, Long> {
      Optional<Member> findByEmail(String email);
}

Spring Data JDBC에서는 CrudRepository라는 인터페이스를 제공하고 있다. 인터페이스내에 정의한 메서드 findByEmail()쿼리 메서드라고 부른다. 해당 쿼리 메서드는 다음과 같이 내부적으로 쿼리문으로 변환된다.
SELECT * FROM MEMBER WHERE MEMBER.EMAIL = ?

또한 @Query 어노테이션을 사용해서 직접 쿼리문을 작성할 수 있다.

public interface MemberRepository extends CrudRepository<Member, Long> {
      Optional<Member> findByEmail(String email);
      
      @Query("SELECT * FROM MEMBER WHERE EMAIL = :email")
      Optional<Member> findByMember(String email);
}

0개의 댓글