Member Repository,Service 개발

코드

package hello.toyProject_1.Repository;

import hello.toyProject_1.domain.Member;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

@Repository
//@Transactional
public class MemberRepositroy {


    @PersistenceContext
    private EntityManager em;

    public Long save(Member member){
        em.persist(member);
        return member.getId();
    }

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

    public List<Member> findAll() {
        return em.createQuery("select m from Member m",Member.class)
                .getResultList();
    }

    public List findByName(String name){
        return em.createQuery("select m from Member m where m.name =:name")
                .setParameter("name",name)
                .getResultList();
    }
}

기술 설명

@Repository

스프링 빈으로 등록한다. @Component 어노테이션이 포함되어 있기 때문에 스캔의 대상이 된다.

@PersistenceContext

EntityManager를 자동으로 생성해서 주입해주는 어노테이션이다. 원래대로면 EntityManagerFactory 를 만들어서 거기서 EntityManager를 생성해야 하는데, 이 과정을 대신 해준다.

persist,@Transactional

JPA가 해당 데이터를 영속성 컨텍스트에 영속시키고 트랜젝션이 끝날 때 COMMIT 한다.
따라서 @Transactional 어노테이션을 통해 포함된 메소드들이 자동으로 transaction 안에서 실행되도록 설정하는데, 이 어노테이션을 service 계층에 놓는 게 맞다고 한다.
왜냐하면 비즈니스 로직 실행시에 오류가 발생하면 그 메소드 자체를 롤백 시켜야 하는데, 이게 리포지토리에 있는 메소드 단위로 실행되면 그게 안된다.

createQuery

JPQL을 작성하는 쿼리이다. JPQL은 테이블 대상으로 작성하는 SQL과 달리, 객체를 대상으로 쿼리를 작성한다는 차이점이 있다. Member, m.name 모두 객체를 의미한다.

  • Service

코드

package hello.toyProject_1.Service;

import hello.toyProject_1.Repository.MemberRepositroy;
import hello.toyProject_1.domain.Member;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
@RequiredArgsConstructor
//@AllArgsConstructor
public class MemberService {

    
    private final MemberRepositroy memberRepositroy;

    public Long join(Member member){
        memberRepositroy.save(member);
        return member.getId();
    }

    public Member findOne(Long id){
        return memberRepositroy.findOne(id);
    }

    public List<Member> getMemberList(){
        return memberRepositroy.findAll();
    }
    
}

기술 설명

@RequiredArgsConstructor

스프링은 자동으로 의존관계 주입을 해주는데, 이를 실행할 수 있는 방법은 크게 3가지가 있다.

  1. 필드
@AutoWired
private emberRepository memberRepository;

@AutoWired 어노테이션을 붙이면, 자동으로 주입해준다. 하지만 이 방식은 필요시에 의존관계를 변경할 수 없다는 단점이 있다.

  1. setter
@AutoWired
public void setMemberRepositroy(MemberRepositroy memberRepositroy) {
        this.memberRepositroy = memberRepositroy;
    }

이 방식은 setter를 통해 계속 주입을 바꿀 수 있다는 특징이 있는데, 때문에 위험하다. 또 처음 생성 이후 의존관계를 바꿀 상황도 거의 없기 때문에 권장하지 않는다.

  1. 생성자 전략
@AutoWired
 public MemberService(MemberRepositroy memberRepositroy) {
        this.memberRepositroy = memberRepositroy;
    }

가장 권장하는 방법으로 생성시에 주입 데이터를 누락하면 컴파일 오류가 발생하기 때문에 사전에 에러발생을 예방할 수 있다.
생성자가 하나만 있으면 자동으로 @AutoWired가 붙기 때문에 생략이 가능하다

@RequiredArgsConstrucctor

이 어노테이션이 붙으면 해당 클래스 안에 final이 붙은 클래스들의 생성자를 자동으로 생성해준다.
lombok 에서 지원하는 기능이다.

TestCase

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
class MemberServiceTest {


    @Autowired MemberService memberService;
    @Autowired MemberRepositroy memberRepositroy;

    @Test
    public void join(){
        //given
        Member member = new Member();
        member.setName("kim");
        //when
        Long id = memberService.join(member);
        Member findMember = memberService.findOne(id);

        //then
        Assertions.assertThat(findMember).isEqualTo(member);

    }

}

기술 설명

@SpringBootTest,@RunWith(SpringRunner.class)

테스트를 스프링부트와 연동해서 실행하기 위한 설정

//given,when,then

Test 코드를 작성하는 문법 중 하나로 //given 에는 테스트를 위해 필요한 클래스들을 선언하고 값을 셋팅, when 에 있는 코드를 실행했을 때 then 에 있는 결과가 나오도록 설계한다.

추가할 것들

  • 중복회원 검증 기능
  • 회원 정보 추가 (전화번호,이메일 등)

좋은 웹페이지 즐겨찾기