@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
// ✔️저장
public void save(Member member) {
em.persist(member);
}
// ✔️아이디로 조회
public Member findOne(Long id) {
Member findMember = em.find(Member.class, id);
return findMember;
}
// ✔️전체 조회
public List<Member> findAll() {
return em.createQuery("select m from Member as m", Member.class).getResultList();
}
// ✔️이름으로 조회
public List<Member> findByName(String name) {
return em.createQuery("select m from Member as m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
}
}
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
private final MemberRepository memberRepository;
@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("이미 존재하는 회원입니다");
}
}
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Member findOne(Long memberId) {
return memberRepository.findOne(memberId);
}
}
@RequiredArgsConstructor
: @Transactional
: 선언적 트랜잭션을 위해 사용되는 어노테이션으로 트랜잭션 기능이 포함된 프록시 객체가 생성되어 자동으로 commit 혹은 rollback을 진행한다.@Transactional(readOnly = true)
: 트랜잭션을 읽기 전용으로 설정하는 것이다.❗@Transactional(rollbackFor = Exception.class)
트랜잭션은 모든 상황에서 롤백시키지는 않는다. 트랜잭션 동작은 어떤 예외가 발생하느냐에 따라 동작 방식이 달라지는데 Unchecked Exception, Error가 발생했을 때는 롤백 처리가 되고, Checked Exception이 발생했을 때는 커밋을 한다. 따라서 모든 예외의 최상위 부모에 있는 Exception을 활용하면 모든 예외에 대해 롤백을 하게 된다.
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
class MemberServiceTest {
@Autowired private MemberService memberService;
@Autowired private MemberRepository memberRepository;
@Autowired private EntityManager em;
@Test
public void 회원가입() throws Exception {
// given
Member member = new Member();
member.setName("kim");
// when
Long savedId = memberService.join(member);
// then
em.flush();
assertEquals(member, memberRepository.findOne(savedId));
}
@Test
public void 중복_회원_예외() throws Exception {
// given
Member member1 = new Member();
member1.setName("kim");
Member member2 = new Member();
member2.setName("kim");
// when
memberService.join(member1);
// then
assertThrows(IllegalStateException.class, () -> memberService.join(member2));
}
}