Spring/JPA

[JPA] JPA 기본

푸라멘 2024. 4. 14. 02:45

JPA(Java Persistence API) 란?

Java ORM 기술에 대한 표준 명세로, JAVA에서 제공하는 API (Spring에서 제공X)

 

※ ORM(Obejcet-relational-mapping) 이란 

  • 객체 관계 맵핑
  • 객체는 객체대로 설계, 관계형 데이터베이스는 관계형 데이터베이스대로 설계
  • 객체와 관계형 데이터베이스를 ORM 프레임워크가 중간에 맵핑 해준다.

 

JPA의 동작 과정

 

 

JPA는 어플리케이션과 JDBC 사이에서 동작한다.

개발자가 JPA를 사용하면 JPA 내부에서 JDBC API 를 사용하여 SQL을 호출하여 DB와 통신한다.

 

 

 

저장 과정

 

 

MemberDAO에서 객체를 저장하고 싶을 때 개발자는 JPA에 Member 객체를 넘기면 JPA는 아래와 같이 동작한다.

1) Member 엔티티를 분석한다.

2) INSERT SQL을 생성한다.

3) JDBC API를 사용하여 SQL을 DB 에 날린다.

 

 

조회 과정

 

 

Member 객체를 조회하고 싶을 때 개발자는 member의 pk 값을 JPA에 넘긴다.

1) 엔티티의 매핑 정보를 바탕으로 적절한 SELECT SQL을 생성한다.

2) JDBC API를 사용하여 SQL을 DB에 날린다.

3) DB로 부터 결과를 받아온다.

4) 결과(ResultSet)를 객체에 매핑한다.

 

 

JPA 사용 준비

build.gradle 에 org.springframework.boot:spring-boot-starter-data-jpa 추가

 

 

Application.properties 정보 설정

EntityManager 객체를 생성할 때 입력한 DB와 JPA 정보를 이용한다.

 

 

Entity생성

@Entity
public class Member {

    //@Id -> PK 역할을 할 속성 지정
    //pk와 pk 생성전략 -> IDENTITY는 DB내에서 생성
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    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;
    }
}

- @Entity  : 테이블과 매핑을 해주는 어노테이션으로 @Entity가 붙은 클래스는 JPA가 관리한다.

- @ Id : 테이블내 Primary Key 역할을 하는 속성을 지정한다.

- @ GeneratedValue : 지정한 속성의 값을 자동으로 생성하는 것을 도와준다. strategy는 value 생성 규칙을 명명하는데 4가지 규칙이 존재한다.

 

  • AUTO (default)
    • persistence provider가 특정 DB에 맞게 자동 선택 ( ex) oracle -> sequence, mysql -> identiy)
  • IDENTITY
    • 기본 키 생성을 DB에 위임한다.
    • em.persist()로 객체를 영속화 시키는 시점에 곧바로 insert 쿼리가 DB로 전송되고, 거기서 반환받은 식별자 값을 가지고 1차 캐시에 엔티티를 등록시켜 관리한다.
  • SEQUENCE 
    • 데이터 베이스 시퀀스를 사용해서 기본키를 할당
  • TABLE
    • 키 생성 전용 테이블을 만들어 시퀀스 처럼사용

 

JpaRepository 생성

//JPA는 transactional 안에서 실행되어야한다.
@Transactional
public class JpaMemberRepository implements MemberRepository{

    //data-jpa 라이브러리를 받으면 spring이 entityManager를 자동으로 생성해준다.
    //application.properties에서 설정한 jpa 정보와 db connection 정보를 가지고있다.
    // @PersistenceContext 통해 의존성 주입을 받을 수도 있다.
    private final EntityManager em;

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

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

    @Override
    public Optional<Member> findById(Long id) {
        // 사용한 class와 class에서 지정한 @Id 속성에 들어갈 값을 parameter로 넣어준다.
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

    @Override
    public Optional<Member> findByName(String name) {
    	// 쿼리작성시 from 뒤 는 DB의 table name이 아닌 java에서 지정한 Class name을 넣어준다.
        // name 속성은 Entity마다 가질 수 도 있고 없을 수도있는데 이러한 속성들을 조회옵션으로 넣으려면
        // :{속성명} 으로 쿼리작성후 setParameter({속성명}, {바꿀 값}) 으로 치환하여 쿼리를 실행한다.
        List<Member> result = em.createQuery("select m from Member m where name= :name", Member.class)
                .setParameter("name", name)
                .getResultList();

        return result.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
        //Entity를 조회하는 쿼리
        List<Member> result = em.createQuery("select m from Member m", Member.class).getResultList();
        return result;
    }
}

 

@Transactional 사용해야하는 이유 

- JPA는 영속성 콘텍스트라는 개념을 Transaction 단위로 갖는다. 불러온 Entity나 EntitiyManager의 persist를 이용해 1차 캐쉬에 등록해 두어 변경사항을 현재 Transaction이 커밋할 때 update를 하게 된다. 이 때 Transaction을 사용하지 않으면 

조회, 저장으로 Transaction 단위가 분리되어 에러가 발생할 수 있다. 

 

 

 

 

Spring Data JPA 

JPA를 쉽게 이용하기 위해 Spring에서 제공하고 있는 모

 

 

 

Spring Data JPA 이용 방법

//JpaRepository를 쓸 떄 <>에 맵핑할 Entity, Entity의 id type을 맞춰 적는다.
//JpaRepository를 상속하면 자동으로 구현체를 만들어 bean으로 등록되어진다.
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {

	// findById, findAll, save 같은 기본 함수들은 구현되어 있다. JpaRepository에 구현되어 있다.

    @Override
    Optional<Member> findByName(String name);

}

 

- 따로 SpringDataJpaMemberRepository를 상속해 구현하는 구현체를 만들지 않아도 된다.

- querydsl을 추가적으로 사용하면 동적 쿼리를 작성 할 수 있다.

 

 

 

JpaRepository가 상속하는 CrudRepository를 보면 기본메서드 있는 것을 확인 할 수 있다.

 

 

 

 

 

 

 

 

참고 문헌