11장은 Spring Framework 와 JPA 를 사용해서 Web Application 을 만들어보는 장입니다. 진행 순서는 다음과 같습니다.

  1. 프로젝트 환경설정
  2. 도메인 모델과 테이블 설계
  3. 기능 구현

코드 위주의 챕터이기 때문에, 핵심 키워드 위주로 정리하려고 합니다.

11.1 프로젝트 환경설정

11.2 도메인 모델과 테이블 설계

11.2.1 요구사항 분석
  • 회원 기능
    • 등록
    • 조회
  • 상품 기능

    • 등록
    • 수정
    • 조회
  • 주문

    • 주문
    • 조회
    • 취소
  • 기타
    • 상품 종류 : 도서 / 음반 / 영화
    • 상품은 카테고리로 구분 가능
    • 상품 주문 시 배송 정보 입력 가능
11.2.2 도메인 모델 설계
  • 회원 / 주문 / 상품
    • 주문과 상품은 다대다 관계
      • 다대다 관계는 관계형 데이터베이스는 물론이고, 엔티티에서도 거의 사용하지 않음
      • 주문 상품이라는 엔티티를 추가해서 다다대 관계를 일대다, 다대일 관계로 풀어냄
    • 상품 분류
      • 상품은 도서, 음반, 영화로 구분되는데, 상품이라는 공통 속성을 사용하므로 상속 구조로 표현
11.2.3 테이블 설계
11.2.4 연관 관계 정리
  • 회원과 주문
    • 일대다 양방향 관계
    • 연관 관계의 주인을 정해야함. 외래키가 있는 주문이 연관 관계의 주인.
  • 주문 상품과 주문
    • 다대일 양방향 관계
    • 주문 상품이 연관관계의 주인
  • 주문 상품과 상품
    • 일대일 단방향 관계
  • 주문과 배송
    • 일대일 양방향 관계
  • 카테고리와 상품
    • @ManyToMany
11.2.5 엔티티 클래스

11.3 애플리케이션 구현

11.3.1 개발 방법
  • Controller
    • MVC 의 컨트롤러가 모여있는 곳
    • 서비스 계층을 호출하고 결과를 뷰에 전달
  • Service
    • 비즈니스 로직이 있고 트렌젝션을 시작
    • 데이터 접근 계층인 Repository를 호출
  • Repository
    • JPA 를 직접 사용하는 곳
    • Entity Manager 를 사용해서 Entity 를 저장하고 조회
  • Domain
    • 엔티티가 모여 있는 계층
    • 모든 계층에서 사용
11.3.2 회원 기능

순수 자바 환경에셔는 엔티티 메니저 팩토리에서 엔티티 메니저를 직접 생성해서 사용했지만, 스프링이나 J2EE 컨테이너를 사용하면 컨테이너가 엔티티 메니저를 관리하고 제공합니다. 그래서, 엔티티 메니저 팩토리에서 엔티티 메니저를 직접 생성해서 사용하지 않고, 컨테이너가 제공하는 엔티티 메니저를 사용합니다.

@PersistenceContext 는 컨테이너가 관리하는 엔티티 메니저를 주입하는 Annotation 입니다.

1
2
@PersistenceContext
EntityManager em;
11.3.3 상품 기능
11.3.4 주문 기능

주문 서비스의 주문과 주문 취소 메소드를 보면 비즈니스 로직 대부분이 엔티티에 있습니다. 서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할을 합니다. 이처럼, 엔티티가 비즈니로스 로직을 가지고 객체지향의 특성을 활용하는 것을 도메인 모델 패턴이라고 합니다.

반대로, 엔티티에는 비즈니스 로직이 거의 없고 서비스 계층에서 대부분의 비즈니스 로직을 처리하는 것을 트랜잭션 스크립트 패턴이라고 합니다.

11.3.5 웹 계층 구현

준영속 엔티티를 수정하는 방법은 2가지입니다.

  • 변경 감지 기능 사용
  • 병합 사용

변경 감지 기능을 사용하는 방법은, 영속성 컨텍스트에서 엔티티를 다시 조회한 후에 데이터를 수정하는 방법입니다.

1
2
3
4
5
6
7
8
@Transactional
//itemParam : Parameter 로 넘어온 준영속 상태의 엔티티
void update(Item itemParam){
//같은 엔티티를 조회
Item findItem = em.find(Item.class, itemParam.getId());

findItem.setPrice(itemParam.getPrice()); //데이터 수정
}

위 코드처럼, 트렌젝션 안에서 준영속 엔티티의 식별자로 엔티티를 다시 조회하면, 영속 상태의 엔티티를 얻을 수 있습니다. 이렇게 영속 상태인 엔티티의 값을 파라미터로 넘어온 준영속 사앹의 엔티티 값으로 변경하면 됩니다. 이렇게 하면, 이후 트렌젝션이 커밋될때 변경감지 기능이 동작해서 데이터베이스에 수정사항이 반영됩니다.

병합은 파라미터로 넘긴 준영속 엔티티의 식별자 값으로 영속 엔티티를 조회하고, 영속 엔티티의 값을 준영속 엔티티의 값으로 채워넣습니다.

1
2
3
4
5
@Transactional
//itemParam : Parameter 로 넘어온 준영속 상태의 엔티티
void update(Item itemParam){
Item mergeItem = em.merge(itemParam);
}

변경 감지 기능을 사용하면, 원하는 속성만 선택해서 변경할 수 있지만, 병합을 사용하면 모든 속성이 변경됩니다.