package jpabook.jpashop.service;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
/**
* 회원가입
* @param member
* @return Long
*/
@Transactional
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());
if(!findMembers.isEmpty()){
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
/**
* 회원 전체 조회
* @param
* @return List<Member>
*/
public List<Member> findMembers(){
return memberRepository.findAll();
}
/**
* 회원 단건 조회
* @param memberId
* @return Member
*/
public Member findOne(Long memberId){
return memberRepository.findOne(memberId);
}
}
@Service
@Service
public class MemberService {
primary key - id
@Transactional
public Long join(Member member){
validateDuplicateMember(member); //중복회원검증
memberRepository.save(member);
return member.getId();
}
public class MemberRepository {
...
public void save(Member member){
em.persist(member);
}
MemberRepository
save
메서드의 em.persist(member)
에서 영속성 컨텍스트에 멤버 객체를 올림
영속성 컨텍스트는 pk인 id
생성을 보장함
validateDuplicateMember()
private void validateDuplicateMember(Member member) {
List<Member> findMembers = memberRepository.findByName(member.getName());
if(!findMembers.isEmpty()){
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
name
컬럼에 unique
제약 조건을 추가하는 것이 안전함@Transactional
@Transactional(readOnly = true)
public class MemberService {
...
@Transactional
public Long join(Member member){
...
jpa의 모든 데이터 변경 로직들은 transaction
안에서 이루어져야 함
findMembers
와 findOne
메서드와 같이 조회만 수행하는 경우에는 readonly
옵션을 true로 설정
위 코드처럼 Service class
에 @Transactional(readOnly = true)
을 걸어놓고 join
메서드는 @Transactional
로 선언을 하면,
join
메서드에 달린 어노테이션이 더 우선권을 가져서 join 시에는 readonly 옵션 없이 변경을 수행하게 됨만약 해당 서비스에서 쓰기 기능만 수행을 한다면 서비스에만 readonly 옵션이 없는 @Transactional
을 붙이는 것이 좋음
@Transactional(readOnly = true)
조회 최적화, 데어터의 변경이 없는 읽기 전용 메서드에 사용
영속성컨텍스트를 Dirty Checking
(변경 감지) 하지 않음
Dirty Checking
flush
하고 디비의 트랜잭션을 Commit
해서 update와 같은 메서드를 사용하지 않고 Entity의 수정이 이루어지는 것commit
했을 때 영속성 컨텍스트가 자동으로 flush
되지 않기 때문에 조회용으로 가져온 entity의 예기치 못한 수정을 방지할 수 있음영속성 컨텍스트를 플러시 하지 않기 때문에 약간의 성능이 향상됨
Snapshot
을 따로 보관하지 않기 때문에 메모리가 절약되는 성능상의 이점도 존재함데이터 변경이 필요한 것에 해당 옵션을 사용하면 변경이 안되기 때문에 주의해서 사용해야 함
@Autowired
@Autowired
@Autowired
private MemberRepository memberRepository;
setter
를 활용한 주입 방식private MemberRepository memberRepository;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
장점 : 테스트시 메서드를 통해 바로 주입이 가능함
단점 : 애플리케이션 로딩 시점에 조립이 모두 이루어지고 런타임에 변경이 이루어질 일은 없음
생성자
주입 방식
- 생성자 주입 방식을 권장
- 변경 불가능한 안전한 객체 생성이 가능해짐
- 생성자가 하나면
@Autowired
를 생략할 수 있음final
키워드를 추가하면 컴파일 시점에memberRepository
를 설정하지 않는 오류를 체크할 수 있음(보통 기본 생성자를 추가할 때 발견)
private MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public static void main(String[] args) {
MemberService memberService = new MemberService(주입 필요);
}
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
생성자가 하나면 @Autowired
를 생략할 수 있음
@Autowired
없이도 생성자가 하나만 있는 경우에는 자동으로 인젝션 해줌final
키워드를 추가하면 컴파일 시점에 memberRepository
를 설정하지 않는 오류를 체크할 수 있음(보통 기본 생성자를 추가할 때 발견)
final
로 선언해야 함또한 아래 세줄로 작성된 생성자 선언 코드는 @RequiredArgsConstructor
로 대체 가능
final
이 있는 필드만 가지고 생성자 선언이 가능해짐활용 전
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
활용 후
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
EntityManager
는 @PersistenceContext
라는 표준 어노테이션이 있어야 인젝션이 가능함
@Autowired
로도 인젝션이 되도록 지원을 해주고 있음따라서 서비스 코드와 같이 리포지토리의 엔티티 매니저를 생성자로 인젝션하도록 코드를 구현할 수 있음
일관성 있는 코드 작성이 가능해짐