본문 바로가기
Back-End/Spring

[Spring] 스프링 DB 접근 기술 - JPA

by 달의 조각 2022. 3. 1.
이 글은 김영한 님의 스프링 입문 강의(https://inf.run/hcic)를 수강하며 학습한 내용을 정리한 글입니다.

 

JPA

  1. 기본적인 SQL을 JPA가 직접 만들어서 실행해 준다.
    JdbcTemplate은 순수 Jdbc 소스 코드보다 단순하지만 SQL은 직접 작성해야 한다는 불편함이 있다.
  2. SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다
  3. 개발 생산성을 크게 높일 수 있다

 

1. build.gradle

spring-boot-starter-data-jpa는 내부에 jdbc 관련 라이브러리를 포함한다.

//  implementation 'org.springframework.boot:spring-boot-starter-jdbc'
   implementation 'org.springframework.boot:spring-boot-starter-data-jap'

Hibernate: 구현체 중 하나

 

2. 스프링 부트에 JPA 설정 추가

// application.properties
spring.jpa.show-sql=true // JPA가 만든 SQL을 볼 수 있다
spring.jpa.hibernate.ddl-auto=none // 테이블 자동 생성 기능 끄기

 

3. JPA 엔티티 매핑

  1. Member클래스 앞에 @Entity 어노테이션을 붙이면 JPA가 관리하는 엔티티가 된다.
  2. @Id로 PK를 설정한다.
    @GeneratedValue(strategy = GenerationType.IDENTITY) : 아이덴티티 전략
  3. name의 DB에서의 컬럼 이름이 username이라면? 매핑 방법: @Column(name = "username")

 

4. JPA 회원 리포지토리 - JpaMemberRepository 생성

  1. MemberRepository 구현(implements MemberRepository)
  2. EntityManager 생성

JPA는 EntityManager로 모든 동작을 한다. JPA 라이브러리를 받으면 자동으로 스프링 부트가 properties의 내용과 데이터베이스 커넥션 정보들을 조합하여 EntityManager을 생성해 준다. 내부적으로 DataSouce를 가지고 있어서 DB와의 통신을 한다. 이제 EntityManager를 주입(injection)받으면 된다

private final EntityManager em;

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

 

5. JpaMemberRepository 코드 작성

1) 저장 - save

    @Override
    public Member save(Member member) {
        em.persist(member); //JPA가 INSERT 쿼리를 만들어서 DB에 넣고, member에 SetId까지 해 준다
        return member;
    }

 

2. 조회 - PK: findById

    @Override
    public Optional<Member> findById(Long id) {
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member); //값이 없을 수도 있으니 Optional 사용
    }

 

3. 조회 - PK 기반이 아닌 나머지: JPQL 쿼리 언어

PK가 아닌 findByName과 findAll은 JPQL을 이용해야 한다. (SQL과 유사하다) 보통 테이블 대상으로 쿼리를 날리는데 JPQL은 엔티티(객체) 대상으로 쿼리를 날리면 SQL로 번역이 된다.

    @Override
    public List<Member> findAll() {
    	//SQL과 달리 id, name 할 필요 없이 매핑이 되어 있어서 멤버 엔티티 자체를 select
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }
    @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();
    }

 

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

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

 

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

// SpringConfig
private EntityManager em; // 엔티티 매니저 생성이 필요하므로 DI

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

댓글