JPA

Sunny·2023년 3월 2일
0

JPA를 사용하면 다음과 같은 장점들이 있다.

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

JPA의 사용 방법은 다음과 같다.

🌱 build.gradle 파일에 JPA, h2 데이터베이스 관련 라이브러리 추가

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  implementation 'org.springframework.boot:spring-boot-starter-web'
  //implementation 'org.springframework.boot:spring-boot-starter-jdbc'
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  runtimeOnly 'com.h2database:h2'
  testImplementation('org.springframework.boot:spring-boot-starter-test') {
 	 exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
  }
}

❗Gradle Refresh 꼭 해줄 것!
✔ spring-boot-starter-data-jpa는 내부에 jdbc 관련 라이브러리를 포함 한다. 따라서 jdbc는 제거해도 된다.


🌱 스프링 부트에 JPA 설정 추가

경로 : resources/application.properties
위의 경로에 다음 설정들을 추가해주면 된다.

👉 JPA가 생성하는 SQL을 출력 할 수 있도록 하는 설정

spring.jpa.show-sql=true

👉 회원 객체를 보고 자동으로 table 생성해주는 기능. 여기서는 이 기능을 껐다.

spring.jpa.hibernate.ddl-auto=none

** create를 사용하면 엔티티 정보를 바탕으로 테이블도 직접 생성해준다.


🌱 JPA 엔티티 매핑

  • 경로: src/main/java/hello/hellospring/domain/Member.java

기존 Member.java에서 다음이 변경되었다.

@Entity
public class Member {
	...
}
  • @Entity를 class에 붙여주면, JPA가 관리하는 엔티티라는 뜻이다.

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
  • @Id : PK라는 뜻이다.
  • @GeneratedValue(strategy = GenerationType.IDENTITY) : Identity 전략(ID 자동 생성)

🌱 JPA 회원 리포지토리

경로 : src/main/java/hello/hellospring/repository/JpaMemberRepository

전체 소스는 다음과 같다.

package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import javax.persistence.EntityManager;
import java.util.List;
import java.util.Optional;

public class JpaMemberRepository implements MemberRepository {

    private final EntityManager em;

    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) {
        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() {
        List<Member> result = em.createQuery("select m from Member m", Member.class)
                .getResultList();
        return result;
    }
}

소스 세부 설명은 다음과 같다.

private final EntityManager em;
  • JPA는 EntityManager로 동작한다. 스프링부트가 자동으로 EntityManager을 생성하면, 우리는 만들어진걸 injection만 하면 된다.

em.persist(member); 
  • 이렇게 하면 JPA가 Insert 쿼리 만들어서 저장한다. id까지 저장해준다.

@Override
public List<Member> findAll() {
    List<Member> result = em.createQuery("select m from Member m", Member.class)
            .getResultList();
    return result;
}
  • JPQL이라는 객체지향 쿼리를 쓰는 것이다.
  • 테이블이 아니라 객체를 대상으로 쿼리를 날린다. 여기서 m은 alias이다.

🌱 서비스 계층에 트랜잭션 추가

  • 경로 : src/main/java/hello/hellospring/service/MemberService.java
@Transactional
public class MemberService {
	...
}
  • JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야한다.
  • 스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.

🌱 JPA를 사용하도록 스프링 변경 설정

  • 경로 : src/main/java/hello/hellospring/SpringConfig.java
package hello.hellospring;

import hello.hellospring.repository.JdbcTemplateMemberRepository;
import hello.hellospring.repository.JpaMemberRepository;
import hello.hellospring.repository.MemberRepository;
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;

@Configuration
public class SpringConfig {

    private final DataSource dataSource;
    private final EntityManager em;

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

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

    @Bean
    public MemberRepository memberRepository() {
        //return new MemoryMemberRepository();
        //return new JdbcMemberRepository(dataSource); // JdbcMemberRepository를 스프링 빈으로 등록
        //return new JdbcTemplateMemberRepository(dataSource);
        return new JpaMemberRepository(em);
    }
}
profile
개발에 재미를 붙여보기 :)

0개의 댓글