스프링/스프링 입문

6/30 스프링 DB 접근 기술 (2) - JPA

born-A 2022. 7. 3. 00:14

JPA

JPA ORM : Object Relational databse Mapping

객체와 relational 데이터베이스 테이블을 매핑한다

 

SQL  쿼리도 JPA가 자동으로 형성해준다

build.gradle에서

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'

추가해주고,

applocation.properties에서 

spring.jpa.show-sql=true 
spring.jpa.hibernate.ddl-auto=none

jpa가 날리는 쿼리 확인 가능

jpa는 자동으로 테이블 생성해주나, 이번 실습에선 이미 member테이블이 만들어져있는 상태이므로

자동으로 테이블 생성해주는 기능은 끈다.

 

jpa는 인터페이스만 제공되는 것이고 그 구현체로hibernate가 있다.

 

매핑은 어떻게?

@Entitiy : JPA가 관리하는 entity가 됨

@ID : pk  매핑

@GeneratedValue(strategy = GenerationType.IDENTITY)

db가 알아서 생성해줌 - identity 전략

 

 

JPA는 entity manager로 모든게 동작을 한다

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

요 부분에서  스프링부트가 자동으로  entity manager를 생성해준다

따라서 만들어진 entitiy manager를 injection 받으면 된다.

private final EntityManager em;

public JpaMemberRepository(EntityManager em){
    this.em = em;
}
@Override
public Member save(Member member) {
    em.persist(member); // persist : 영구적으로 저장한다 보면 됨
    return member;
}

->JPA가 id까지 member에 setId까지 다해준다.

@Override
    public List<Member> findAll() {
        List<Member> result = em.createQuery("select m from Member m", Member.class).getResultList();
        return result;
    }
}

inline 단축키 : shift + option + enter

@Override
public List<Member> findAll() {
    return em.createQuery("select m from Member m", Member.class).getResultList();
}

요렇게 합쳐짐

@Override
public Member save(Member member) {
    em.persist(member); // persist : 영구적으로 저장한다 보면 됨
    return member;
}

@Override
public Optional<Member> findById(Long id) {
    Member member = em.find(Member.class, id);
    return Optional.ofNullable(member)
}

@Override
public Optional<Member> findByName(String name) {
    List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
            .setParameter("name", name) .getResultList();
    return result.stream().findAny();
}

@Override
public List<Member> findAll() {
    return em.createQuery("select m from Member m", Member.class).getResultList();
}

pk기반이 아닌 findByName, findAll의 경우에는 쿼리를 작성해주어야 한다.

 

JPA를 쓸려면 항상 transaction이 있어야 한다.

서비스 계층에 @Transactional 해준다. 데이터를 저장하거나 변경할 땐 transaction이 있어야 한다.

모든 데이터 변경이 transaction 안에서 실행이 되어야한다.

@Transactional
public class MemberService {

스프링 설정 변경

@Configuration
public class SpringConfig {
    private EntityManager em;
    
    @Autowired
    public SpringConfig(EntityManager em){
        this.em = em;
    }
    
    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository()); }
    @Bean
    public MemberRepository memberRepository() { //    return new MemoryMemberRepository();
        //return new JdbcMemberRepository(dataSource); }
        //return new JdbcTemplateMemberRepository(dataSource);
        return new JpaMemberRepository(em);
    }
}

 

스프링 데이터 JPA

리포지토리에구현클래스없이 인터페이스만으로 개발 완료 가능.

반복 개발해온 기본 CRUD 기능도 스프링데이터 JPA가 모두 제공한다.

public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
    Optional<Member> findByName(String name);
}

인터페이스가 인터페이스를 받을 때에는 extends, 인터페이스는 다중상속이 가능

JpaRepository를 상속받고 있으면  스프링 데이터 JPA가 구현체를 만들어서 스프링 빈에 등록해준다

 

 

@Configuration
public class SpringConfig {
    private final MemberRepository memberRepository;

    @Autowired
    public SpringConfig(MemberRepository memberRepository) {
        this.memberRepository = memberRepository; 
    }


    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository); 
    }
}

스프링 설정 수정

스프링데이터 JPA 제공기능 인터페이스를통한기본적인 CRUD
findByName(), findByEmail() 처럼 메서드 이름 만으로 조회 기능 제공, 페이징 기능 자동 제공