Files
2021-12-13 21:23:43 +09:00

6.5 KiB

JPA

  • JPA는 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.
  • JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다.
  • JPA를 사용하면 개발 생산성을 크게 높일 수 있다.
  • 객체를 JPA에 넣으면 JPA가 중간에서 DB에 SQL을 날리고 데이터를 가져오는 등의 처리를 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'
    }
}
  • spring-boot-starter-data-jpa 는 내부에 jdbc 관련 라이브러리를 포함한다. 따라서 jdbc는 제거해도 된다.

스프링 부트에 JPA 설정 추가

resources/application.properties

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none

주의

스프링부트 2.4부터는 spring.datasource.username=sa 를 꼭 추가해주어야 한다. 그렇지 않으면 오류가 발생한다.

  • show-sql : JPA가 생성하는 SQL을 출력한다.
  • ddl-auto : JPA는 테이블을 자동으로 생성하는 기능을 제공하는데 none 를 사용하면 해당 기능을 끈다.
    • create 를 사용하면 엔티티 정보를 바탕으로 테이블도 직접 생성해준다.

JPA 엔티티 매핑

  • JPA를 사용하려면 먼저 Entity를 매핑해야한다.
  • JPA는 인터페이스만 제공한다. 그리고 구현 기술들이 여러개가 있는데, 우리는 Hibernate만 사용한다고 생각하면 된다.
  • JPA는 자바진영의 표준 인터페이스이고 구현은 여러 업체들이 하는 것이라 생각하면 된다. 각 업체별로 차이점이 조금씩 있다.
  • ORM(Object Relational Mapping) : 객체와 관계형 데이터베이스의 테이블을 매핑한다는 뜻이다.
  • @Entity(javax.persistence.Entity)를 클래스에 선언하면 해당 클래스는 JPA가 관리하는 엔티티가 된다.
  • 그 다음으로는 PK를 매핑해줘야 한다(@Id 사용). 또, 현재 우리는 데이터베이스에서 자동으로 ID를 생성해주고 있는데 이를 IDENTITY전략이라고 부르며 @GeneratedValue(strategy = GenerationType.IDENTITY)로 선언한다.
  • 특정 필드를 DB에 있는 특정 컬럼명과 매핑할 때, 해당 필드에 @Column(name = "컬럼명")을 선언해주면 된다.
  • 이렇게 어노테이션들을 통해서 데이터베이스의 테이블과 매핑하면 JPA가 해당 정보를 가지고 각종 쿼리들을 처리해준다.

JPA 회원 리포지토리

@Transactional
public class JpaMemberRepository implements MemberRepository {

    private final EntityManager entityManager;

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

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

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

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = entityManager.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 entityManager.createQuery("select m from Member m", Member.class)
                .getResultList();
    }
}
  • 'org.springframework.boot:spring-boot-starter-data-jpa' 라이브러리를 받으면 스프링 부트가 자동으로 설정 정보와 데이터베이스 커넥션 정보등을 이용해서 EntityManager라는 것을 생성해준다. 그럼 우리는 이걸 그대로 주입받으면 된다.
  • JPAEntityManager라는 것으로 모든게 동작한다. 결론적으로 JPA를 사용하려면 EntityManager를 주입받아야 한다.
  • EntityManager는 내부적으로 DataSource를 가지고 있어서 DB와 통신하는 등의 행위를 알아서 처리한다.
  • persist 는 영구저장(영속화)하다 라는 뜻이다. 이렇게 하면JPA가 알아서 insert 쿼리를 만들어 DB에 집어넣고 setId까지 모든걸 다 해준다.
  • inline 단축키 : Ctrl + Alt + N
  • PK의 경우는 그냥 조회할 수 있지만(EntityManager.find() 이용) 그 외에 PK 기반이 아닌 것들은 JPQL이라는 객체지향 쿼리언어를 사용해야 한다(거의 SQL과 똑같다).
    • 객체를 대상으로 쿼리를 날리면 SQL로 번역이 된다.
    • select의 대상이 객체(Entity) 그 자체이다.
  • JPA를 사용하려면 항상 @Transactional이 선언되어 있어야 한다.
  • org.springframework.transaction.annotation.Transactional 를 사용하자.
  • 스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
  • JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.

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

@Configuration
public class SpringConfig {

    private EntityManager entityManager;

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

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

추가 설명

  • spring-data-jpa를 세팅하면 기본적으로 Hibernate라는 오픈소스 구현체가 사용된다.