[Spring] 입문 6-5. JPA

강우엉·2023년 7월 5일

Spring

목록 보기
19/359

JDBC에서 JDBC Template 변경해보면 코드가 확 간결해졌지만,
SQL은 사용자가 작성해야한다.

  • JPA는 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.
  • JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다.
  • JPA를 사용하면 개발 생산성을 크게 높일 수 있다.

라이브러리를 추가해보자.
build.gradle 파일에서
implementation 'org.springframework.boot:spring-boot-starter-jdbc'를 주석처리하고
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'를 추가해준다. 내부에 jdbc 관련 라이브러리를 포함한다. 따라서 jdbc는 제거해도
된다.

resources/application.properties에도 설정을 추가해줘야 한다.
spring.jpa.show-sql=true 는 jpa가 날리는 sql 확인이 가능해진다.
spring.jpa.hibernate.ddl-auto=none jpa를 사용하면 객체를보고 테이블을 생성하는데 우리는 만들어진것을 확인할거기에 끄고 시작한다. none이 아닌 create로 하면 테이블도 자동생성된다.

spring.datasource.url = jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa

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

JPA 엔티티 매핑을 해주자.
domain/member 클래스에서
@Entity라는 어노테이션을 붙여 JPA가 관리하는 엔티티로 만든다.
@Id를 통해 PK도 매핑해줘야 한다.
@GeneratedValue(strategy = GenerationType.IDENTITY) 코드를 통해 자동 증가 해주는 값임을 명시한다.

name도 만약 DB에 컬럼명이 username 이라면 아래 주석과 같은 코드로 매핑해준다.

package hello.hellospring.domain;

import javax.persistence.*;

@Entity
public class Member { // 비즈니스 도메인 객체, 데이터베이스에 저장하고 관리됨.

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
	
    //@Column(name = "username")
    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;
    }
}

이제 JpaMemberRepository를 생성하고 아래와 같이 코드를 작성하자.
build.gradle에서 라이브러리를 받으면 스프링부트가 자동으로 엔티티메니저를 생성해준다. 만들어진것을 인젝션 받으면된다.

   private final EntityManager em;

    public JpaMemberRepository(EntityManager em) {
        this.em = em;
    }

save 구현
jpa가 insert 쿼리 만들어서 집어놓고 setId까지 다 해준다.

	@Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }

findById 구현
조회할 타입과 식별자 넣어주면 select문 생성

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

findAll 구현
엔티티를 대상으로 쿼리를 날림.

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

findByName 구현

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

JPA를 사용할시 주의할 점은 항상 트랜잭션이 있어여한다.
따라서 MemberService에 @Transactional생성한다.
스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야한다.

@Transactional
public class MemberService { // 핵심 비즈니스 로직 구현 (비즈니스에 가까운 용어들을 사용하는것이 일반적 repository와 반대)

}

SpringConfig 파일 수정해준다.
JpaMemberRepository를 return 해준다.
엔티티매니저가 필요하다. 따라서 아래코드로 di 해준다.

package hello.hellospring;

import hello.hellospring.repository.*;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;
import javax.sql.DataSource;
import javax.swing.text.html.parser.Entity;

@Configuration
public class SpringConfig {

    private EntityManager em;

    @Autowired
    public SpringConfig(EntityManager em) {
        this.em = em;
    }

    //    @Autowired
//    public SpringConfig(DataSource dataSource) {
//        this.dataSource = dataSource;
//    }

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

}

이제 통합테스트를 통해 돌려보면 성공하는것을 알 수 있다.
값이 제대로 들어가는지 확인하고싶다면, 회원가입 위에 @Commit 어노테이션을 붙여주면 DB에 값이 잘들어가는지 확인 가능하다.

profile
우엉이의 코딩 성장일기💻

0개의 댓글