[실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발] 04. 회원 도메인 개발

Turtle·2024년 7월 4일
0
post-thumbnail

🙄회원 리포지토리 개발

@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 :
      • 해당 어노테이션은 Lombok에서 지원하는 어노테이션이다.
      • 해당 어노테이션은 생성자를 통해 의존성을 주입하는 방식을 지원한다.
      • final 키워드가 붙은 필드에 대해 생성자를 만들어준다.
      • 생성자를 통한 의존성 주입을 권장하는 이유는 한 번 의존성 주입을 받은 객체는 프로그램이 종료될 때까지 변하지 않는 불변을 보장하기 때문이다.
    • @Transactional : 선언적 트랜잭션을 위해 사용되는 어노테이션으로 트랜잭션 기능이 포함된 프록시 객체가 생성되어 자동으로 commit 혹은 rollback을 진행한다.
    • @Transactional(readOnly = true) : 트랜잭션을 읽기 전용으로 설정하는 것이다.
  • ✔️트랜잭션
    • 데이터베이스 상태를 변경하는 작업 또는 한 번에 수행되어야 하는 연산들을 의미한다.
    • begin, commit을 자동으로 수행해준다.
    • 예외 발생 시 rollback 처리를 자동으로 해준다.
    • 트랜잭션은 4가지 속성(ACID)을 가지고 있다.
  • ✔️원자성 - Atomicity
    • 한 트랜잭션 내에서 실행한 작업들은 하나의 단위로 처리한다.
  • ✔️일관성 - Consistency
    • 트랜잭션은 일관성 있는 데이터베이스 상태를 유지한다.
  • ✔️고립성 - Isolation
    • 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 해야 한다.
  • ✔️영속성 - Durability
    • 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.

❗@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));
	}
}

0개의 댓글