
✅ 제거 : implementation 'org.springframework.boot:spring-boot-starter-jdbc'
✅ 추가 :implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
spring.jpa.show-sql=true : JPA가 생성하는 SQL을 출력한다
spring.jpa.hibernate.ddl-auto=none : JPA는 테이블을 자동으로 생성하는 기능을 제공하는데 none을 사용하면 해당 기능을 끈다.
create를 사용하면 엔티티 정보를 바탕으로 테이블도 직접 생성해준다.package com.hello.hellospring.domain;
import jakarta.persistence.*;
// jpa에서 관리하는 엔터티임
@Entity
public class Member {
// Id는 pK
// db가 id를 자동으로 생성하는 것 -> 아이덴티티 전략이라고 함
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// db랑 연결되는 네임
// @Column(name="uesrname")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity : JPA에서 관리하는 엔터티이다.@Id : PK@GeneratedValue(strategy = GenerationType.IDENTITY) : db가 id를 자동으로 생성하는 것@Column : 칼럼의 속성@Id 어노테이션을 추가할 때 import 되는 부분이
import org.springframework.data.annotation.Id; 이 아닌
import jakarta.persistence.Id; 이어야 함!
JPA 설정과 엔티티와의 매핑을 마쳤다. 이제 JPA 회원 리포지터리를 생성해보자!
package com.hello.hellospring.repository;
import com.hello.hellospring.domain.Member;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Optional;
public class JpaMemberRepository implements MemberRepository {
// bulid 하면 자동으로 엔터티매니저라는 객체를 만들어줌
private final EntityManager em;
// JPA를 쓰려면 엔터티매니저를 주입해줘야 한다.
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
@Override
public Member save(Member member) {
// 영구적으로 저장하다
em.persist(member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
// find(조회할 클래스, 식별자)
Member member = em.find(Member.class, id);
return Optional.ofNullable(member);
}
@Override
public Optional<Member> findByName(String name) {
return em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name).getResultList().stream().findAny();
}
@Override
public List<Member> findAll() {
// ctrl + alt + n : inline
// sql문에서 객체 자체를 셀렉트함
return em.createQuery("select m from Member m", Member.class).getResultList();
}
}
💻 MemberService에 @Transactional 추가
package com.hello.hellospring.service;
import com.hello.hellospring.domain.Member;
import com.hello.hellospring.repository.MemberRepository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
;
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
@Transactional
// JPA는 트랜잭션이 있어야함
/*
회원 가입
*/
public Long join(Member member){
validateDuplicateMember(member); // 중복회원 검증
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName()).ifPresent(member1 -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/*
전체 회원 조회
*/
public List<Member> findMembers(){
return memberRepository.findAll();
}
/*
아이디 찾기
*/
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
package com.hello.hellospring.service;
import com.hello.hellospring.repository.JpaMemberRepository;
import com.hello.hellospring.repository.MemberRepository;
import jakarta.persistence.EntityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
private EntityManager em;
public SpringConfig(EntityManager em) {
this.em = em;
}
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new JpaMemberRepository(em);
}
}
package com.hello.hellospring.service;
import com.hello.hellospring.domain.Member;
import com.hello.hellospring.repository.MemberRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
// 자동으로 롤백됨
@Transactional
class MemberServiceIntergrationTest {
@Autowired MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Test
// @Commit 붙이면 db에 저장됨
void join() {
// given 주어진 것
Member member = new Member();
member.setName("홍길동");
// when
Long id = memberService.join(member);
// then
Member result = memberService.findOne(id).get();
assertThat(member.getName()).isEqualTo(result.getName());
}
@Test
void 중복_회원_예외() throws Exception{
// given
Member member1 = new Member();
member1.setName("홍길동");
Member member2 = new Member();
member2.setName("홍길동");
// when
memberService.join(member1);
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
// memberService.join(member1);
// try{
// memberService.join(member2);
// fail();
// } catch(IllegalStateException e){
// assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
// }
}
}
