등록 할 때
@Service
@Transactional
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
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("이미 존재하는 회원입니다.");
}
}
@Transactional(readOnly = true)
public List<Member> findMembers() {
return memberRepository.findAll();
}
@Transactional(readOnly = true)
public Member findOne(Long memberId) {
return memberRepository.findOne(memberId);
}
}
@Transactional(readOnly = true)
으로 읽기 전용을 알려주면 리소스나 성능 최적화가 가능하다.@Transactional(readOnly = true)
를 설정하고 쓰기에만 기본 @Transactional
을 주는 것도 가능하다. 그렇게 바꿔 보자.name 중복 체크가 이렇게만 하면 위험하다. 혹시라도 동 타이밍에 입력이 들어올 수 있기 때문에 DB에서 unique제약 조건을 걸어서 최후의 방어 수단으로 DB 레벨에서 걸러 낼 수 있도록 하자.
기본 생성자 주입을 사용하는 이유 (생성자 인젝션)
테스트 코드 등에서 외부에서 repository를 주입할 수가 있다. setter를 만드는 것도 가능한데 단점은 실수로 누군가가 setter를 통해서 실수로 repository를 변경할 수 있다.
최신 스프링은 생성자가 하나만 있는 경우 생성자에 @Autowired
를 생략해도 된다. final 어노테이션도 넣는 것이 좋다.
그리고 이것을 쉽게 하려면! 롬복의 @AllArgsConstructor
그리고 또 이것보다 한번 더 좋은 건 @RequiredArgsConstructor
이다. 예는 final 필드만 가지고 생성자를 만든다!!
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
// ...