# 회원 서비스 개발

구현할 내용

1. 회원 가입 : 중복 회원 방지 익셉션 메서드 추가
2. 회원 조회 : 회원 전체 조회, 회원 단건 조회

<메서드 구현>

* join(Member member) : **member.getId() 해도 값이 있다는 것이 보장된다!**\
  MemberRepository의 save()에서 em.persist(member)하는 순간 영속성 컨텍스트에 member객체를 넣을 때 영속성 컨텍스 (key,value)에서 key는 **PK**가 된다.\
  **Member 테이블의 PK**는 **id(name="member\_id")**&#xC774;다. @GenerateValue는 DB마다 다른데, 어떤 것은 테이블을 아예 따로 만들어서 key를 가져오는 것도 있고, 어떤 것은 시퀀스를 만들어 넣는다.\
  **그렇기 때문에 em.persist(member)할 때 id값이 항상 생성되있는 것이 보장된다!**\
  **왜냐하면 영속성 context할 때 값을 넣어야 하고, 그 때 구조는 (key,value)인데 key는 PK 값을 그대로 넣음과 동시에 Member 클래스 필드의 값도 채워준다.(DB에 들어가는 시점이 아니여도)**
* **join 메서드에** 중복 회원 체크 추가(메서드 추가 구현)\
  동시에 동일한 이름으로 회원가입하는 경우가 있다! 그러므로 멀티스레드 환경을 고려해서 DB에 member.getName()을 유니크 제약조건으로 잡아야한다!\
  최적화 : 단순히 갯수만을 체크해서 0보다 큰 조건으로 해줘도 된다!
* findMembers() : 회원 전체 조회

  ```
  public List<Member> findMembers() {
    return memberRepository.findAll();
  }
  ```
* findOne(Long memberId) : 회원 단건 조회

  ```
  public Member findOne(Long memberId) {
    return memberRepository.findOne(memberId);
  }
  ```

<기술 설명>

1. **MemberService 클래스에 @Transactional(readOnly = true)로 설정**

MemberService 클래스에는 읽기 메서드가 많기 때문에 상위 클래스에 @Transactional(readOnly = true)로 해주고 쓰기 메서드인 join은 @Transactional로 해준다!(디폴트값은 readOnly=false)\
\
JPA 의 모든 데이터 변경이나 로직은 모두 트랜잭션 내에서 다 실행되어야 하기 때문에 @Transactional 애노테이션 필요!\
@Transactinal은 자바와 스프링에서 제공하는 2가지가 있는데 스프링에 의존적인 애플리케이션을 개발하는 것이기 때문에 스프링에서 제공하는 것을 선택해야 기본 기능 외에 확장된 기능까지 사용할 수 있다!\
\
@Transactinal을 전체 클래스 레벨에 적용하면 내부의 메서드들도 다 적용이 되는데, 이 @Transactional을 조회하는 메서드에 개별로 붙이고, redOnly=true를 넣어주면 **JPA가 조회**하는 것에 있어서 **성능이 최적화**된다! 그렇기 때문에 조회하는 읽기 전용 메서드는 @Transactional(readOnly = true)로 해준다!\
\- dirtycheck를 하지 않는 이점\
\- readOnly(읽기 모드)기 때문에 DB도 리소스를 많이 쓰지 않고 읽기만 함

**2. 인젝션(의존 관계 주입 DI) : @Autowired**\
**생성자 Injection 많이 사용. 생성자 하나면 생략 가능**

1. 필드 인젝션\
   스프링 빈에 등록된 MemberRepository를 의존 관계 주입한다!=>해당 필드 수정 어렵다!

   ```
   @Autowired
   private MemberRepository memberRepository;
   ```

2. setter 인젝션(수정자 주입)\
   장점 : 테스트코드 작성시에 파라미터 직접 주입해줄 수 있음.\
   단점 : 실제 애플리케이션이 돌아가는 시점에 누군가가 값을 셋팅해서 바뀔 수 있다!\
   하지만 실제로 애플리케이션 런타임에는 뭔가가 바뀔 수가 없고, 바뀌어서도 안된다!

3. **constructor 인젝션(생성자 주입), 해당 필드는 final로 설정**\
   생성될 때 딱 한번 주입된다!\
   다만, 메인 메서드에서 MemberService  객체 인스턴스 생성할 때, 파라미터로 뭐라도 넣어줘야함!\
   최신 스프링에서는 생성자가 딱 하나일 때는 @Autowired를 생략해도 자동으로 인젝션해준다!\
   final로 설정하면 무조건 값이 있어야하기 때문에 값을 안 넣어주면 컴파일에러로 알려주기 때문이다!

   ```
   private final MemberRepository memberRepository;
   @Autowired
   public MemberService(MemberRepository memberRepository){
       this.memberRepository = memberRepository;
   }
   ```

4. (롬복)@AllArgsConstructor : 모든 필드를 생성자주입해준다!

5. **(롬복)@RequiredArgsConstructor : final 붙은 필드들만 생성자주입해준다!(추천)**

6. **MemberRepository에서 EntityManager 의존 관계 주입⭐️**\
   EntityManager는 표준 의존 관계 주입(DI) 애노테이션@PersistenceContext가 있어야 한다. 하지만 스프링 부트 JPA가 @Autowired로도 DI 지원해주기 때문에 다른 DI들과 마찬가지로 해줘도 된다!\
   원래 소스 :@PersistenceContext로 스프링이 JPA의 EntityManager를 생성해서 자동 주

```
@PersistenceContext
private EntityManager em;
```

마찬가지로 MemberRepository에서도 EntityManager 필드를 생성자 주입 가능!

```
@PersistenceContext//스프링이 JPA의 EntityManager 생성해서 자동 주입.
private EntityManager em;

public MemberRepository(EntityManager em){
    this.em = em;
}
```

이때, @PersistenceContext를 그냥 @Autowired로 해도 된다. 스프링 부트의 JPA가 지원해준다.

```
@Autowired
private EntityManager em;

public MemberRepository(EntityManager em){
    this.em = em;
}
```

최종 : MemberRepository 클래스에 @RequiredArgsConstructor해주고  필드 final로 설정.

![](https://1491120136-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MeIsSQVBsQu8Hb7mOOk%2F-MeNKpq80QJOPGwuFmsH%2F-MeNL1SPPeo6stBIAq3q%2FScreen%20Shot%202021-07-12%20at%2010.32.00%20AM.png?alt=media\&token=a5737cae-a59d-4e3a-92ad-9b6bd52dd86f)
