Spring Data JPA를 통한 데이터 액세스 계층 구현

seongmin·2022년 11월 5일
0

Spring

목록 보기
33/38
post-thumbnail

Spring Data JDBC에서 사용했던 코드에서 몇가지 내용들이 추가된다.

Entity

@NoArgsConstructor
@Getter
@Setter
@Entity
public class Member {
	...
    ...
    // (1)
    @Enumerated(value = EnumType.STRING)
    @Column(length = 20, nullable = false)
    private MemberStatus memberStatus = MemberStatus.MEMBER_ACTIVE;

    @Column(nullable = false)
    private LocalDateTime createdAt = LocalDateTime.now();

    @Column(nullable = false, name = "LAST_MODIFIED_AT")
    private LocalDateTime modifiedAt = LocalDateTime.now();

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

    public Member(String email) {
        this.email = email;
    }

    public Member(String email, String name, String phone) {
        this.email = email;
        this.name = name;
        this.phone = phone;
    }

    public void addOrder(Order order) {
        orders.add(order);
    }

    // (2) 
    public enum MemberStatus {
        MEMBER_ACTIVE("활동중"),
        MEMBER_SLEEP("휴면 상태"),
        MEMBER_QUIT("탈퇴 상태");

        @Getter
        private String status;

        MemberStatus(String status) {
           this.status = status;
        }
    }
}
  • (1)은 회원의 상태를 저장하기 위해 추가된 enum 필드다. 처음 회원이 등록될 때의 기본 값은 MemberStatus.MEMBER_ACTIVE 이고, 일정 기간이 지나서 회원의 활동이 없거나 회원이 탈퇴를 원하면 ‘MEMBER_SLEEP(휴면 상태)’ , ‘MEMBER_QUIT(탈퇴 상태)’ 등으로 변경될 것이다.

  • (2)는 (1)에서 정의된 memberStatus에서 사용하는 MemberStatus enum 이다. 현재는 ‘MEMBER_ACTIVE(활동중)’ , ‘MEMBER_SLEEP(휴면 상태)’ , ‘MEMBER_QUIT(탈퇴 상태)’ 이렇게 총 세 개의 회원 상태를 사용할 수 있도록 구성되어 있다.

다른 엔티티 클래스도 위와 같은 식으로 내용들을 추가하면 된다.

Repository

public interface CoffeeRepository extends JpaRepository<Coffee, Long> {//(1) 수정된 부분
    Optional<Coffee> findByCoffeeCode(String coffeeCode);

    // (2) 수정된 부분
//    @Query(value = "FROM Coffee c WHERE c.coffeeId = :coffeeId")  // (2-1)
//    @Query(value = "SELECT * FROM COFFEE WHERE coffee_Id = :coffeeId", nativeQuery = true) // (2-2)
	@Query(value = "SELECT c FROM Coffee c WHERE c.coffeeId = :coffeeId")  // (2-3)
    Optional<Coffee> findByCoffee(long coffeeId);
}

Spring Data JDBC에서의 MemberRepository와 비교했을때 변경된 부분은 (1)과 같이 CrudRepository 를 상속하는 대신 JpaRepository 를 상속하는 것이다.

사실 JpaRepository 를 상속하지 않고, CrudRepository 를 상속해도 되지만 JpaRepository가 JPA에 특화된 더 많은 기능들을 포함하고 있기 때문에 사용한다.


(2)에 대한 설명

JPA에서는 복잡한 검색 조건을 지정하기 위한 몇 가지 방법을 제공한다.

  • JPQL을 통한 객체 지향 쿼리 사용

JPA에서는 JPQL이라는 객체 지향 쿼리를 통해 데이터베이스 내의 테이블을 조회할 수 있다.

JPQL은 데이터베이스의 테이블을 대상으로 조회 작업을 진행하는 것이 아니라 엔티티 클래스의 객체를 대상으로 객체를 조회하는 방법이다.

JPQL의 문법을 사용해서 객체를 조회하면 JPA가 내부적으로 JPQL을 분석해서 적절한 SQL을 만든 후에 데이터베이스를 조회하고, 조회한 결과를 엔티티 객체로 매핑한 뒤에 반환한다.

(2-3)은 JPQL을 사용해서 coffeeId에 해당하는 커피 정보를 조회하고 있다. JPQL의 쿼리문을 보면 SQL과 유사하지만 차이점이 있다.

JPQL은 객체를 대상으로 한 조회이기 때문에 COFFEE 테이블이 아니라 Coffee 클래스라는 객체를 지정해야하고, coffee_id라는 컬럼이 아닌 coffeeId 필드를 지정해야 한다.

따라서 (2-3)의 “SELECT c FROM Coffee c WHERE c.coffeeId = :coffeeId”에서 Coffee는 클래스명이고, coffeeId는 Coffee 클래스의 필드명이다.

‘c’는 Coffee 클래스의 별칭이기 때문에 “SELECT c FROM~” 와 같이 SQL에서 사용하는 ‘*’이 아니라 ‘c’로 모든 필드를 조회하는 것이다.

(2-3)은 (2-1)과 같이 ‘SELECT c’를 생략한 형태로 사용이 가능하다.

  • 네이티브 SQL을 통한 조회

Spring Data JDBC에서와 마찬가지로 JPA 역시 네이티브 SQL 쿼리를 작성해서 사용할 수 있다.

(2-2)의 nativeQuery 애트리뷰트의 값을 true 로 설정하면 value 애트리뷰트에 작성한 SQL 쿼리가 적용된다.

0개의 댓글