회원 도메인 개발

회원 리포지토리 개발

// 컴포넌트 스캔에 의해 자동으로 빈으로 관리된다.
@Repository
public class MemberRepository {

    // 스프링이 EntityManager를 주입해준다.
    @PersistenceContext
    private EntityManager em;

    public void save(Member member) {
        em.persist(member);
    }

    public Member findOne(Long id) {
        return em.find(Member.class, id);
    }

    public List<Member> findAll() {
        // 리스트는 jpql을 사용해야 한다.
        // sql은 테이블을 대상으로, jpql은 객체를 대상으로 쿼리한다는 점이 다르다.
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }

    public List<Member> findByName(String name) {
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name) // :name 파라미터 바인딩
                .getResultList();
    }
}

@Repository

  • 스프링 빈으로 등록된다.

  • JPA 예외를 스프링 기반 예외로 변환한다.

@PersistenceContext

  • EntityManager를 주입한다.

  • 직접 긴 코드를 쓸 필요가 없어졌다.

@PersistenceUnit

  • EntityManagerFactory를 주입한다.

회원 서비스 개발

@Transactional

  • javax와 springframework 두 가지 종류가 있다.

    • 이미 스프링에 의존이 많이 되어있기 때문에 javax보다는 springframework를 import하는 게 좋다.

    • 그래야 쓸 수 있는 옵션도 더 다양하다.

  • readOnly = true

    • 더티 체킹을 안하거나 DB 옵션에 따라 읽기 전용 모드로 읽는 등 성능상 이점이 있다.

    • 기본을 true로 두고 변경이 필요한 곳에만 false로 달아두면 된다.

조회가 아니라면 true일 때 데이터 변경이 안되므로 주의하자. 커맨드성이 강해서 조회가 거의 없다면 기본 값으로 두는 게 더 좋다.

@Autowired

  • @Autowired로 필드 주입을 하면 엑세스할 방법이 없어서 다른 의존성으로 바꿔치기 할 수가 없다.

  • setter 주입을 쓰면 직접 mock 등을 주입해줄 수 있는 장점이 있다.

  • 애플리케이션 동작 시점에 누군가가 setter에 접근해서 바꿀 수 있는 위험이 있다.

  • 생성자 주입을 하면 생성된 이후에는 바꿀 수 없어서 좋다.

  • 객체 생성 시 의존성을 넣어주도록 컴파일 타임에 강제한다.

    • 주입해야 한다는 사실을 안 놓치고 안전하게 개발할 수 있다.

  • 스프링 최신 버전에서는 생성자가 하나만 있는 경우 @Autowired가 없어도 알아서 생성해준다.

  • 이때 private final로 선언해주는 것이 좋다.

    • 값 세팅을 안하면 컴파일 시점에 체크해주기 때문이다.

  • 롬복 @AllArgsConstructor를 쓰면 생성자를 대체할 수 있다.

  • @RequiredArgsConstructor는 final인 필드만 생성자를 만들어준다.

  • @AllArgsConstructor보다 추천한다.

  • 스프링 데이터 JPA 덕분에 EntityManager도 생성자 주입으로 받을 수 있다.

회원 기능 테스트

회원 가입

예제에서는 이해를 돕기 위해 통합적으로 테스트를 할 것이다.

  • @RunWith(SpringRunner.class)

    • 스프링과 테스트를 통합한다.

  • @SpringBootTest

    • 스프링 부트를 띄워서 테스트한다.

    • 이게 없으면 @Autowired는 다 실패한다.

  • @Transactional

    • 반복 가능한 테스트를 지원한다.

      • 즉, 각 테스트 실행마다 테스트가 끝나면 트랜잭션을 롤백한다.

      • 자동 롤백은 테스트 케이스에서만 적용된다.

select만 나가고 실제 회원 가입을 하면서 생겨야 할 insert 쿼리는 나가지 않았다.

  • DB 전략마다 다르지만 기본적으로 persist만 하면 쿼리가 나가지 않는다.

  • 트랜잭션이 commit될 때 flush 되면서 쿼리가 나가는 것이기 때문이다.

  • @Transactional이 자동으로 롤백을 하니까 당연히 insert 쿼리를 보내지 않는 것이다.

    • 정확하게는 영속성 컨텍스트가 flush를 하지 않는다.

  • @Rollback에 false 옵션을 주어야 커밋이 실행된다.

정상적으로 insert 쿼리가 나간 것을 볼 수 있다.

중복 회원 예외

  • expected에 터질 예정인 예외를 써준다.

테스트를 위한 설정

  • 테스트는 완전히 격리된 환경에서 실행하는 것이 좋다.

  • 끝나면 데이터를 초기화하기 위해 메모리 DB를 사용한다.

testresources를 따로 만들어두면 테스트 시에 mainresources보다 우선권을 가진다.

하이버네이트는 jvm 위에 띄워 인 메모리 방식으로도 사용할 수 있다.

심지어 이렇게 간단하게만 설정해도 돌아간다. 스프링 부트는 따로 설정이 없다면 자동으로 메모리 모드로 돌려주기 때문이다.

스프링은 기본적으로 create-drop으로 돌아간다.

  • create

    • 먼저 drop한 후 애플리케이션을 실행한다.

  • create-drop

    • create와 똑같이 동작한 뒤에 종료 시점에 다시 drop 시킨다.

    • 인 메모리는 어차피 WAS가 내려가면 다 사라지기 때문에 중요하진 않다.

Last updated

Was this helpful?