JPA1/Section.3,4(인프런,김영한) 리뷰

김민석·2023년 5월 9일
0

JPA

목록 보기
3/4
post-thumbnail

Section3,4

section 3,4는 애플리케이션 구현 준비 및 직접개발을 하는 과정이다

구현할 화면과 기능이다.

어플리케이션 아키텍쳐이다.
controller에서 바로 Repository로 접근할 수 있는 구조로 설계할 예정이다.

실습 코드

다음은 코드인데 기능 및 세부사항은 주석을 참고하면 된다.

package jpabook.jpashop.repository;
import jakarta.persistence.EntityManager;
import jpabook.jpashop.domain.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository//component scan에 의해 자동으로 spring Bean에서 관리 해준다.
@RequiredArgsConstructor //injection 해줌
public class MemberRepository {

    private final EntityManager em;
    //spring이 생성한 entity manager를 주입 받음 원래라면 entity manager factory에서 꺼내 써야하는데 따로 그럴 필요가없다
    //만일 entity manager factory를 주입 받고 싶다면 @PersistenceUnit /n private EntityManagerFactory emf;
    
     public void save(Member member){
         em.persist(member);//영속성 context에 member객체를 넣음
     }
     public Member findOne(Long id){
         return em.find(Member.class, id);
         // 단건 조회 find(타입,PK)
     }

     public List<Member> findAll(){
         return em.createQuery("select m from Member m", Member.class)
                 .getResultList();
         //qlString은 sql과 기능은 거의 동일하지만 sql테이블을 대상으로 쿼리를 하는 반면
         // qlString은 Entity객체를 대상으로 쿼리한다.
     }
     public List<Member> findByName(String name){//이름으로 검색
         return em.createQuery("select m from Member m where m.name=:name",Member.class)
                 .setParameter("name",name)
                 .getResultList();
     }//파라미터 바인딩후 특정이름 회원 찾기
}
package jpabook.jpashop.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
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(readOnly = true)
//jakarta가 제공하는것 보다 spring이 제공하는 기능이 더 많다
//읽기 전용에는 readOnly = true 추가 해주자
//@AllArgsConstructor public MemberService~~~안써도됨 lombok적용
@RequiredArgsConstructor // private final있는 필드만 가지고 생성자를 만들어준다. 원래 setter나 생성자 injection을 써야됨
public class MemberService {

    private final MemberRepository memberRepository;

    //@Autowired 이 없어도 자동으로 memberRepository를 injection 해줌

    /**
     * 회원 가입
     */
    @Transactional//쓰기 전용에는 readOnly = true 추가 하면 안됨 값이 바뀌지 않는다
    public Long join(Member member){
        validateDuplicateMember(member); //중복 회원 검증
        memberRepository.save(member);//동시에 회원가입 하는경우 동시에 호출가능
        return member.getId();
    }

    // 중복회원 검증
    private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getName());
        //실무에서는 동시에 회원 가입하는 경우를 대비해 unique 제약조건으로 잡아주는것을 권장
        if (!findMembers.isEmpty()) {
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        }
    }
    //회원 전체 조회
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }
    //1건만 조회
    public Member findOne(Long memberId){
        return memberRepository.findOne(memberId);
    }

}

테스트 서비스

package jpabook.jpashop.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import static org.junit.Assert.*;
/*
테스트 요구사항
회원가입을 성공해야 한다.
회원가입 할 때 같은 이름이 있으면 예외가 발생해야 한다.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MemberServiceTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;
   // @Autowired EntityManager em; query보여줌

    @Test
    public void 회원가입() throws Exception {
        //given
        Member member = new Member();
        member.setName("kim");

        //when
        Long saveId = memberService.join(member);

        //then
        assertEquals(member, memberRepository.findOne(saveId));

    }//같은 Transaction안에 같은 Entity id값이 똑같다면 같은 영속성 context에서 똑같은 것이 관리가 된다
    @Test(expected = IllegalStateException.class)
    public void 중복_회원_예외() throws Exception{
        //given
        Member member1 =new Member();
        member1.setName("kim");

        Member member2 =new Member();
        member2.setName("kim");

        //when
        memberService.join(member1);
        memberService.join(member2);//예외가 발생해야 한다

        //then
        fail("예외가 발생해야 한다.");
    }

}

annotation

Spring의 대표적인 Annotation과 역할

@Component
개발자가 생성한 Class를 Spring의 Bean으로 등록할 때 사용하는 Annotation이다.

@ComponentScan
Spring Framework는 @Component, @Service, @Repository, @Controller, @Configuration 중 등록된 클래스를 찾으면, Context에 bean으로 등록한다. @ComponentScan이 있는 클래스의 하위 Bean을 등록 될 클래스들을 스캔하여 Bean으로 등록해줍니다.

@Bean
@Bean Annotation은 개발자가 제어가 불가능한 외부 라이브러리와 같은 것들을 Bean으로 만들 때 사용합니다.

@Controller
Spring에게 해당 Class가 Controller의 역할을 한다고 명시하기 위해 사용하는 Annotation입니다.

@RequestHeader
Request의 header값을 가져올 수 있으며, 해당 Annotation을 쓴 메소드의 파라미터에 사용한다.

@RequestMapping
@RequestMapping(value="~~")와 같은 형태로 작성하며, 요청 들어온 URl의 요청과 Annotation value 값이 일치하면 해당 클래스나 메소드가 실행된다.

URI란(Uniform Resource Identifier)?
URI 뜻은 우리말로 ‘통합 자원 식별자’
Uniform은 리소스를 식별하는 통일된 방식을 말합니다.
Resource란, URI로 식별이 가능한 모든 종류의 자원(웹 브라우저 파일 및 그 이외의 리소스 포함)을 지칭합니다.
Identifier는 다른 항목과 구분하기 위해 필요한 정보입니다.
즉, URI는 인터넷상의 리소스 “자원 자체”를 식별하는 고유한 문자열 시퀀스입니다.

@SpringBootTest
Spring Boot Test에 필요한 의존성을 제공해줍니다.

@Autowired
Spring Framework에서 Bean 객체를 주입받기 위한 방법은 크게 아래의 3가지가 있습니다. Bean을 주입받기 위하여 @Autowired 를 사용합니다. Spring Framework가 Class를 보고 Type에 맞게(Type을 먼저 확인 후, 없으면 Name 확인) Bean을 주입합니다.

Lombok의 대표적인 Annotation

Lombok은 코드를 길이를 줄여주어 가독성을 높여 준다.

@Setter
Class 모든 필드의 Setter method를 생성해줍니다.

@Getter
Class 모든 필드의 Getter method를 생성해줍니다.

@AllArgsConstructor
Class 모든 필드 값을 파라미터로 받는 생성자를 추가합니다.

@NoArgsConstructor
Class 기본 생성자를 자동으로 추가해줍니다.

@ToString
Class 모든 필드의 toString method를 생성한다.

@Entity
어노테이션이 선언된 클래스를 DB 테이블과 매핑합니다.

Test 실행전 Settings에 있는 Gradle에 들어가 Runtests Using을 Intellij로 바꾸지않으면 에러가 뜨면서 실행이 되지 않는다.

테스트

참고로 테스트에서 db는 memory mode로 띄웠다.
resource directory 생성후 application.yml 복붙해준다.
h2.com들어가서 cheat sheet 들어가서 In Memory에 jdbc:h2:mem:test복사해서 application.yml의 url에 복붙을 했다.


메모리 모드 application.yml 세팅

0개의 댓글