자바 ORM 표준 JPA 프로그래밍 - JPA 시작

Song Chae Won·2023년 5월 21일
0
post-thumbnail

2장부터 JPA를 사용하여 테이블 하나를 등록(c), 조회(r), 수정(u), 삭제(d) 하는 JPA 애플리이션을 만들어보겠다!!🤩

2.1 이클립스 설치와 프로젝트 불러오기

  • 이클립스 대신에 인텔리제이를 사용할 계획이다!

https://medium.com/@oopchoi/jpa-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-fc443b647ec8
위의 내용을 참고하여서 인텔리제이에 예제 프로그램을 설치하였다.

2.2 H2 데이터베이스 설치

  • 기존에 이펍 세션에서 다운 받은 H2 데이터베이스가 있어서 이어서 실행하였다.

🔻 예제 테이블 생성

2.3 라이브러리와 프로젝트 구조

메이븐(Maven)

  • 자바 라이브러리와 빌드를 관리하는 도구. 라이브러리를 자동 다운로드할 수 있고 의존성 관리가 가능하다.

  • pom.xml의 에 사용할 라이브러리를 지정하면 라이브러리(jar파일)를 메이븐 공식 저장소에서 내려받아 다운로드할 수 있다.

🔻메이븐 설정파일인 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>org.jpa-basic</groupId>
    <artifactId>ex-1-hello-jpa</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--JPA 하이버네이트 : 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>2.1.214</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

</project>
  • <dependencies>에 사용할 라이브러리를 지정한다. groupId + artifactId + version만 적어주면 라이브러리(jar 파일)를 메이븐 공식 저장소에서 내려받아 라이브러리에 추가해준다.

  • JPA, 하이버네이트(hibernate-entitymanager): JPA 표준과 하이버네이트를 포함하는 라이브러리, hibernate-entitymanager를 라이브러리로 지정하면 다음 중 두 라이브러리도 함께 내려받는다.
    - hibernate-core.jar
    - hibernate-jpa-2.1-api.jar

2.4 객체 매핑 시작

🔻 매핑정보가 포함된 회원 클래스

package jpabook.start;

import javax.persistence.*;  

@Entity
@Table(name="MEMBER")
public class Member {

  @Id
  @Column(name = "ID")
  private String id;

  @Column(name = "NAME")
  private String username;

  private Integer age;

  public String getId() {
      return id;
  }

  public void setId(String id) {
      this.id = id;
  }

  public String getUsername() {
      return username;
  }

  public void setUsername(String username) {
      this.username = username;
  }

  public Integer getAge() {
      return age;
  }

  public void setAge(Integer age) {
      this.age = age;
  }
}

매핑 어노테이션

☑️ @Entity
이 클래스를 테이블과 매핑한다고 JPA에게 알려준다. 이렇게 @Entity가 사용된 클래스를 엔티티 클래스라 한다.

☑️ @Table
엔티티 클래스에 매핑할 테이블 정보를 알려준다. 여기서는 name 속성을 사용해서 Member 엔티티를 MEMBER 테이블에 매핑했다. 이 어노테이션을 생략하면 클래스 이름을 테이블 이름으로 매핑한다. (정확히는 엔티티 이름을 사용한다.)

☑️ @Id
엔티티 클래스의 필드를 테이블의 기본 키(Primary key)에 매핑한다. 여기서는 엔티티의 id 필드를 테이블의 ID 기본 키 칼럼에 매핑했다. 이렇게 @Id가 사용된 필드를 식별자 필드라 한다.

☑️ @Column
필드를 칼럼에 매핑한다. 여기서는 name 속성을 사용해서 Member 엔티티의 userName 필드를 MEMBER 테이블의 NAME 컬럼에 매핑했다.

☑️매핑 정보가 없는 필드
age 필드에는 매핑 어노테이션이 없다. 이렇게 매핑 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑한다. 여기서는 필드명이 age이므로 age 컬럼으로 매핑했다. 참고로 이 책에서는 데이터베이스가 대소문자를 구분하지 않는다고 가정한다. 만약 대소문자를 구분하는 데이터베이스를 사용하면 @Column(name = "AGE") 처럼 명시적으로 매핑해야 한다.

매핑 정보 덕분에 JPA는 어떤 엔티티를 어떤 테이블에 저장해야 하는지 알 수 있다. JPA 어노테이션의 패키지는 javax.persistence이다.

2.5 persistence.xml에 설정

🔻 JPA 환경설정 파일 persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
    <persistence-unit name="jpabook">
        <properties>
            <!--필수 속성-->
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javaxx.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.user_sql_comments" value="true"/>

        </properties>
    </persistence-unit>
</persistence>
  • persistence-unit : 영속성 유닛으로, 일반적으로 연결할 데이터베이스 당 하나의 영속성 유닛을 등록하고, 고유한 이름을 부여한다. 위의 코드에서는 jpabook이라는 이름을 이용

  • javax.persistence : JPA 표준 속성. hibernate 말고 다른 구현체 라이브러리를 사용해도 사용할 수 있다.

  • hibernate : hibernate 전용 속성. hibernate를 사용하는 경우에만 사용할 수 있다.

➡️ 사용한 속성을 보면 데이터베이스에 연결하기 위한 설정이 대부분인데, 여기서 가장 중요한 속성은 데이터베이스 방언을 설정하는 hibernate.dialect이다.

데이터베이스 방언

JPA는 특정 데이터베이스에 종속되지 않는다. Dialect란 SQL표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능을 JPA에서 지칭하는 말이다.


개발자는 JPA가 제공하는 표준 문법에 맞추어 JPA를 사용하면 되고, 특정 데이터베이스에 의존적인 SQL은 데이터베이스 방언이 처리해준다. 따라서 데이터베이스가 변경되어도 애플리케이션 코드를 변경할 필요없이, 데이터베이스 방언만 교체하면 되고, 방언 설정 방법은 JPA에 표준화되어있지 않다.

🔻 하이버네이트가 제공하는 데이터베이스 방언
H2 : org.hibernate.dialect.H2Dialect
Oracle 10g : org.hibernate.dialect.Oracle10gDialect
MySQL : org.hibernate.dialect.MySQL5Dialect

2.6 애플리케이션 개발

🔻애플리케이션 시작 코드

package jpabook.start;

import javax.persistence.*;
import java.util.List;

public class JpaMain {

    public static void main(String[] args) {

        //엔티티 매니저 팩토리 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
        EntityManager em = emf.createEntityManager(); //엔티티 매니저 생성

        EntityTransaction tx = em.getTransaction(); //트랜잭션 기능 획득

        try {


            tx.begin(); //트랜잭션 시작
            logic(em);  //비즈니스 로직
            tx.commit();//트랜잭션 커밋

        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback(); //트랜잭션 롤백
        } finally {
            em.close(); //엔티티 매니저 종료
        }

        emf.close(); //엔티티 매니저 팩토리 종료
    }

    public static void logic(EntityManager em) {

        String id = "id1";
        Member member = new Member();
        member.setId(id);
        member.setUsername("채원");
        member.setAge(20);

        //등록
        em.persist(member);

        //수정
        member.setAge(24);

        //한 건 조회
        Member findMember = em.find(Member.class, id);
        System.out.println("findMember=" + findMember.getUsername() + ", age=" + findMember.getAge());

        //목록 조회
        List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
        System.out.println("members.size=" + members.size());

        //삭제
        em.remove(member);

    }
}
  

엔티티 매니저 설정

🔻엔티티 매니저 팩토리 생성

  • JPA를 시작하려면 persistence 클래스를 사용하여 엔티티 매니저 팩토를 생성해야한다. 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야함

🔻엔티티 매니저 생성

  • JPA 기능의 대부분은 엔티티 매니저가 제공한다. 엔티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회 할 수 있다. 엔티티 매니저는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드간에 공유하거나 재사용하면 안된다.

🔻종료

  • 사용이 끝난 엔티티 매니저와 엔티티 매니저 팩토리는 반드시 종료해야함.

트랜잭션 관리

JPA 사용하면 항상 트랜잭션 안에서 데이터를 변경해야하고, 트랜잭션 없이 데이터를 변경하면 예외가 발생한다.

EntityTransaction tx = em.getTransaction(); //트랜잭션 기능 획득

    try {
          tx.begin();  //트랜잭션 시작
          logic(em);   //비즈니스 로직
          tx.commit(); //트랜잭션 커밋

        } catch (Exception e) {
          e.printStackTrace();
          tx.rollback(); //예외 발생 시트랜잭션 롤백
  }
  

트랜잭션 API를 사용해서 비즈니스 로직이 정상 동작하면 트랜잭션을 커밋하고 예외가 발생하면 트랜잭션을 롤백한다.

비즈니스 로직

회원 엔티티를 하나 생성한 다음, 엔티티 매니저를 통해 데이터베이스에 등록, 수정, 삭제, 조회한다.

public static void logic(EntityManager em) {

        String id = "id1";
        Member member = new Member();
        member.setId(id);
        member.setUsername("채원");
        member.setAge(20);

        //등록
        em.persist(member);

        //수정
        member.setAge(24);

        //한 건 조회
        Member findMember = em.find(Member.class, id);
        System.out.println("findMember=" + findMember.getUsername() + ", age=" + findMember.getAge());

        //목록 조회
        List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
        System.out.println("members.size=" + members.size());

        //삭제
        em.remove(member);

    }

등록, 수정, 삭제, 조회 작업이 엔티티 매니저를 통해서 수행되는 것을 알 수 있고 엔티티 매니저는 객체를 저장하는 가상의 데이터 베이스처럼 보인다.

JPQL

      //목록 조회
      List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
      System.out.println("members.size=" + members.size());

JPA는 엔티티 객체를 중심으로 개발하므로 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색해야함. 그런데 엔티티 객체를 대상으로 검색하려면 데이터베이스의 모든 데이터를 애플리케이션으로 불러와서 객체로 변경한 후에 검색해야하는데 사실상 불가능하다! 애플리케이션이 필요한 데이터만 데이터베이스에서 불러오려면 검색조건이 포함된 SQL을 사용해야하므로 JPQL이라는 쿼리 언어를 사용해야한다.

JPQL과 SQL 문법 차이

  • JPQL은 엔티티 객체를 대상으로 쿼리한다. 클래스와 필드를 대상으로 쿼리
  • SQL은 데이터베이스 테이블을 대상으로 쿼리
profile
@chhaewxn

0개의 댓글