프로젝트 환경설정
@PersistenceContext
private EntityManager em;
- 엔티티 매니저를 통한 모든 변경은 항상 트랜잭션 안에서 이루어져야하기 때문에 트랜잭션을 걸어줘야 함
@Transactional이 테스트 케이스에 있으면 테스트가 끝난 다음 바로 롤백 > 실제로 데이터 저장 X
- 롤백을 적용하기 싫으면
@Rollback(false) 애너테이션 사용
@Test
@Transactional
public void testMember() throws Exception{
...
}
도메인 분석 설계
- 실무에서 가급적이면 Getter는 열어두고, Setter는 필요한 경우에만 사용하는것이 좋음
- 임베디드타입은 기본생성자를 public으로 두는 것 보다는 protected로 설정하는것이 더 안전 > 기본생성자를 사용해 새로운 객체를 생성하는것을 막기 위해서
@Embeddable
@Getter
public class Address{
private String city;
private String street;
private String zipcode;
protected Address(){
}
public Address(String city, String street, String zipcode){
this.city=city;
this.street=street;
this.zipcode=zipcode;
}
}
엔티티 설계시 주의점
- 엔티티에는 가급적 Setter 사용 X
- 모든 연관관계는 지연로딩으로 설정하기 > 연관된 엔티티를 함께 조회하고 싶으면 fetch join을 사용
- 컬렉션은 필드에서 바로 초기화하는 것이 안전 > 처음에 생성하고 가급적 변경 X
회원 도메인 개발
@Transactional
- JPA의 모든 데이터 변경이나 로직들은 가급적 트랜잭션 안에서 실행이 되어야 함
@Transactional > 스프링이 제공하는 애너테이션을 사용하는것이 더 좋음
- 조회하는 곳에서는
@Transactional(readOnly=true)을 사용하면 성능을 최적화
- 읽기가 아닌 쓰기에서는
readOnly=true 옵션을 넣으면 데이터 변경 X
메모리DB로 테스트
- 테스트를 할 때 외부에있는 DB를 사용하게 되면 테스트를 병렬로 여러개씩 돌리거나할 때 어려움 발생
- 테스트는 끝나면 메모리가 초기화 되는것이 좋음
- 테스트를 완전히 격리된 환경, 메모리 DB를 사용
- test에 resources 디렉토리를 만들어서 기존
application.yml을 복사
application.yml 파일에서 url을 메모리로 바꾸면 됨 --> jdbc:h2:mem:test > 메모리 모드로 동작
- DB 띄우지 않고 바로 test만 돌려도 됨
- 스프링부트는 별도의 설정이 없으면 다 메모리 모드로 돌림 > 따로 설정이 없으면 메모리 모드로 돌아감!!!!
- 운영과 테스트의 application.yml은 분리해야함 (운영에서의 설정과 테스트에서의 설정이 다르기 때문)
상품 도메인 개발
- 엔티티와 관련된 핵심 비즈니스 로직은 그냥 엔티티 내에 생성해서 사용하는것이 좋음 > 객체지향
주문 도메인 개발
@NoArgsConstructor(access = AccessLevel.PROTECTED) > 기본 생성자를 protected로 막는 롬복 애너테이션
- 엔티티에 핵심 비즈니스 로직을 몰아넣는것을 도메인 모델 패턴이라고 함 > 서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할
- 반대로 서비스계층에서 대부분의 비즈니스 로직을 처리하는 것은 트랜잭션 스크립트 패턴
- 현재 내 문맥에서 뭐가 더 맞는지를 보고 선택해서 사용
- 테스트는 통합테슽보다 단위테스트를 하는것이 더 좋음
웹 계층 개발
- 대부분 엔티티를 직접 사용하는것보다 폼객체를 만들어서 필요한 데이터만 알맞게 사용하도록 하는것이 좋음
변경감지와 병합
준영속 엔티티를 수정하는 2가지 방법
- 변경 감지 기능 (dirty checking) 사용
- 병합 (merge) 사용 : 준영속 상태의 엔티티를 영속 상태로 변경
em.merge(item);
merge()를 실행
- 파라미터로 넘어온 준영속 엔티티의 식별자 값(pk)으로 1차 캐시에서 엔티티를 조회, 없으면 DB에서 조회하고 1차캐시에 저장
- 조회한 영속 엔티티에 준영속 엔티티의 값을 채워넣음
- 영속 엔티티를 반환
- 변경감지를 사용하면 원하는 속성만 변경할 수 있으나, 병합을 사용하면 모든 속성이 변경됨 > 병합시 값이 없으면 null로 업데이트 할 수 있음
- 병합보다 변경감지를 사용해야함
- 컨트롤러에서 엔티티를 생성하지 않는것이 좋음, 그냥 필요한 값만 넘겨주기
- 트랜잭션이 있는 서비스 계층에서 영속 상태의 엔티티를 조회하고, 엔티티의 데이터를 직접 변경
- 필드 하나하나 setter를 사용하는것보다 변경하는 메서드를 하나 만들어서 한번에 수정하도록하고, 병합보다 변경감지를 사용하기
출처
[인프런] 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발