WEB/JPA

김영한 (ORM 표준 JPA 프로그래밍 2) JPA 시작하기

Tony Lim 2021. 2. 25. 01:01

 

JPA를 쓰러면 기본적인 설정 하는 persistence.xml 파일을 resource/META-INF 폴더 안에 만들어서 넣어주어야한다.

<?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>

현재는 연습용으로 h2 를 쓴다. javax. 다른 jpa 구현체를 써도 그대로 유지되지만 hibernate. 시작하는것은 구현체마다 다르게 다른것을 적어주어야 한다.

hibernate.show_sql = db 에 나가는 쿼리를 눈으로 확인하겠다 라는 옵션이다.

 

데이터베이스 방언

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

각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 다름

 

JPA 구동 방식

 

객체와 테이블을 생성하고 매핑하기

H2 에 member table을 생성해주고 그에 해당하는 JPA가 관리하는 객체를 생성해준다. 

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;
    }
}

private key설정은 필수다. JPA 에게 니가 관리해야할 Entity 임을 알려주어야한다.

@Table(name="USER") 라는 것을 통해 실제 db에 table이름이 USER이면 거기로 전달되게 할 수 있다.

@Column(name = "username") 을 통해서도 실제 db column 이름을 매핑 시킬 수 가 있다.

이제 한번 Member 한놈을 저장해보자

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)
    {
        // emf 는 딱 하나만 만들어야한다.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        // 트랜잭션 단위를 실행할떄마다 생성해주어야한다. dbconnection 을 얻어서 쿼리를 날리고 종료하는
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        Member member = new Member();
        member.setId(1L);
        member.setName("HelloA");
        em.persist(member);

        tx.commit();


        em.close();

        emf.close();

    }
}

모든것은 transaction 안에서 이루어져야한다. 

Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)

hibernate.show.sql , hibernate.format_sql ,hibernate.use_sql.comments 덕분에 보이는 것이다. 

좀더 정석적으로 짠 코드는 아래와 같다.

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)
    {
        // emf 는 딱 하나만 만들어야한다.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        // 트랜잭션 단위를 실행할떄마다 생성해주어야한다. dbconnection 을 얻어서 쿼리를 날리고 종료하는
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();
        
        try
        {
            Member member = new Member();
            member.setId(1L);
            member.setName("HelloA");
            em.persist(member);
            tx.commit();
        }
        catch (Exception e)
        {
            tx.rollback();
        }
        finally
        {
            em.close();
        }
        emf.close();
    }
}

문제가 생길시 롤백을 해준다. 이코드들은 스프링을 사용하면 다 사라진다.

삭제 = em.remove() , 조회 = em.find() 를 통해서 한다. 수정시에는 아래와 같다.

            Member findMember = em.find(Member.class, 1L);
            findMember.setName("HelloJPA");

            tx.commit();

em.persist() 를 통해서 저장 할 필요가없다. 자바의 컬렉션 처럼 동작하게 만들었기 때문이다. @Entity 가 들어가있으면 JPA가 스스로 관리하기에 뭔가 변경이 있으면 tx.commit() 직전에 update query를 작성하여 날려준후 커밋이 된다.

 

주의

EntityMangerFactory 는 하나만 생성해서 애플리케이션 전체에서 공유

EntityManager 는 쓰레드간에 공유하면안되고 사용하고 버려야한다. databaseconnection처럼 바로 돌려주어야한다.

JPA의 모든 데이터 변경은 transaction 안에서 실행해야 한다. 조회는 그냥 해도 된다.

 

JPQL 조건부 쿼리를 보내고싶을 때 써야한다.

검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색, db에 종속적으로 되지않는다.

JPQL = 엔티티 객체를 대상으로 쿼리 , SQL = 데이터베이스 테이블을 대상으로 쿼리