[JPA]/JPA 프로그래밍 - 기본편

[JPA] JPA 시작하기

쿠릉쿠릉 쾅쾅 2022. 3. 26. 18:03
728x90

 

 

프로젝트 생성

인텔리제이 → File → new → project... → maven  

1. 메이븐 라이브러리 - pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>jpa-basic</groupId>
    <artifactId>ex1-hello-jpa</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <!-- JPA 하이버네이트 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.3.10.Final</version>
        </dependency>
        <!-- H2 데이터베이스 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
        </dependency>
    </dependencies>
</project>

 

2. JPA 설정 - persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="hello">
        <properties>
            <!-- 필수 속성 -->
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

            <!-- 옵션 -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments" value="true"/>
            <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>
</persistence>
  • 파일 위치
    • resureces/META-INF/persistence.xml
  • persistence-unit namehello로 지정

 

3. JPA는 특정 데이터베이스에 종속되지 않는다.

  • JPA는 특정 데이터베이스에 종속되지 않는다.
  • hibernate.dialect 속성으로 데이터베이스 방언을 지정할 수 있다.
    • 데이터베이스 방언 : SQL 표준을 지키지 않는 특정 데이터베이스만의 고유한 기능
    • H2 : org.hibernate.dialect.H2Dialect
    • Oracle 10g : org.hibernate.dialect.Oracle12cDialect
    • MySQL : org.hibernate.dialect.MySQL5Dialect
    • 하이버네이트는 40가지 이상의 데이터베이스 방언을 지원한다.

 

4. JPA 구동 방식 - maven

  • 엔티티 매니저 팩토리(EntityManagerFactory)는 하나만 생성해서 애플리케이션 전체에서 공유한다.
  • 엔티티 매니저(EntityManager)는 쓰레드간에 공유하면 안된다. (사용하고 버려야 한다.)
    • 고객의 요청이 올 때마다 엔티티 매니저를 쓰고 버린다. 재사용 x
  • JPA의 모든 데이터 변경은 트랜잭션(Transaction) 안에서 실행해야 한다.

 

5. 객체, 테이블 생성 후 매핑

package hellojpa;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Member {

    @Id
    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 : JPA가 관리할 객체
  • @Id : 데이터베이스 PK와 매핑

테이블 생성

create table Member (
    id bigint not null,
    name varchar(255),
    primary key (id)
);

 

6. 실습

회원 등록

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try {
            Member member = new Member();
            member.setId(2L);
            member.setName("HelloB");

            em.persist(member);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}

회원 수정

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try {
            Member findMember = em.find(Member.class, 1L);
            findMember.setName("HelloJPA");
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}
  • 저장된 데이터를 수정할 때는 자바 컬렉션처럼 수정된 객체를 다시 저장하지 않아도 된다. 
  • find 메서드를 통해서 가져온 객체의 값을 setter 메서드로 필드 값을 변경한다. 그러면 commit() 호출 시 적용되기 전 시스템에서 변경감지를 통해 기존 객체와 차이점을 찾아서 업데이트를 자동으로 해준다.

회원 삭제

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try {
            Member findMember = em.find(Member.class, 1L);
            em.remove(findMember);
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}

회원 단 건 조회

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try {
            Member findMember = em.find(Member.class, 1L);
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}

 

7. JPQL 소개

  • JPQL은 JPA에서 제공하는 객체지향 쿼리다.
  • 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
  • SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다.
  • JPA는 JPQL을 분석한 후 적절한 SQL을 만들어 데이트베이스를 조회한다.
  • 식별자를 통한 단순 조회가 아닌 추가 조건들을 통해 조회를 하고자 할 때 사용된다.
    • JPA에서 단순 PK값으로만 find() 하는 것이 아니기 때문에 여러가지 조건으로 검색하는 쿼리를 위해 JPQL이 필요하다.
    • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하기 때문이다.
  • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
    • SQL과 문법이 유사하다. SELECT / FROM / WHERE / GROUP BY / HAVING / JOIN 문법을 지원한다.

회원 전체조회

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try {
            List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .getResultList();

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}
  • 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
    • 일반 쿼리와 다르게 From 절 Member는 테이블이 아닌 엔티티(Member.class)를 대상으로 한다.

테이블이 아닌 엔티티를 사용한 쿼리의 장점은?

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try {
            List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .setFirstResult(5)  // JPQL 페이징 처리
                    .setMaxResults(8)   // JPQL 페이징 처리
                    .getResultList();

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}
  • 페이징처리를 할 때 각 DB의 방언에 따라 지원하는 메서드가 다르다.
  • 하지만 JPQL을 사용하 DB를 바꿔도 JPQL 코드를 바꾸지 않아도 된다.

 

🧷 (참고) Querydsl

  • Querydsl은 JPQL을 편하게 작성할 수 있게 도와주는 JPQL 빌더 역할을 한다.
  • Querydsl은 오픈 소스이므로 라이브러리를 설치해야 한다.
  • Querydsl은 자바 코드이기 때문에 컴파일 시점에서 에러를 잡을 수 있어서 좋다.

Querydsl 기본 문법

Querydsl vs JPQL

  • 복잡한 쿼리나 동적쿼리를 사용할 때 Querydsl을 사용한다.
  • 진짜 매우 단순한 경우에만 JPQL로 작성한다.
  • 사실상 대부분 쿼리를 Querydsl로 작성해야한다고 보면 된다.

 

 

 

 


👀 참고 자료

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

https://catsbi.oopy.io/0a48ff61-ee46-4909-b5b4-d5f63937195f

 

JPA 소개 & 시작하기

JPA 소개

catsbi.oopy.io

 

https://developer-minji.tistory.com/m/87

 

7. Querydsl 적용

JPQL과 Querydsl JPQL은 JPA에서 제공하는 가장 중요한 객체지향 쿼리 언어이다. JPQL 특징 테이블이 아닌 객체를 대상으로 검색하는 객체지향 쿼리다. SQL을 추상화해서 특정 데이터베이스 SQL에 의존

developer-minji.tistory.com

 

https://www.inflearn.com/questions/38771

 

Querydsl과 jpql을 선택하는 차이가 궁금합니다. - 인프런 | 질문 & 답변

드디어 querydsl을 배우고있네요! 제가 이해하고 있기로는, jpa에서 단순히 PK값으로 find()만 하는것이 아니기 때문에 여러가지 조건으로 검색하는 쿼리를 위해 jpql이 존재하는 것이고, jpql로 해결하

www.inflearn.com

 

728x90