LUMI_dev

2. Hello JPA 실습_ H2 데이터베이스 설치와 실행, JPA와 JPQL기본(EntityManagerFactory,@Id,@Table 등 ) 본문

JPA/자바 ORM 표준 JPA 프로그래밍 - 기본편

2. Hello JPA 실습_ H2 데이터베이스 설치와 실행, JPA와 JPQL기본(EntityManagerFactory,@Id,@Table 등 )

luminous_dev 2025. 3. 8. 02:24

 

1. https://h2database.com/html/main.html

 

H2 Database Engine

H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2.5 MB jar file size     Supp

h2database.com

 

가볍고 / 웹용 쿼리툴 제공 / MySQL, Oracle 데이터베이스 시뮬레이션 기능 / 시퀀스,AutoIncrement 기능 지원

 

2. 윈도우는 bat 파일 

 

 

 

3. JDBC 설정 후 실행 

 

 

4. 아래 부분에 쿼리 작성 

 

 

maven

자바 라이브러리, 빌드 관리

라이브러리 자동 다운로드 및 의존성 관리

최근에는 그래들(Gradle)이 점점 유명 

 

프로젝트 생성

자바 8이상

 

메이븐 설정 

groupId : jpa-basic

artifactId: ex1-hello-jpa

version : 1.0.0 

 

 

pom.xml 추가

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

 

 

 

resources > META-INF > 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"> <!--jpa 이름은 뭘로 쓸 것인지-->
        <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"/><!--데이터베이스 방언 : SQL 표준을 지키지 않는 특정 DB만의 고유 기능-->
<!--            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>-->
<!--            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>-->
            <!-- 옵션 -->
            <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>

 

 

JPA 구동 방식

 

 

 

 

@Entity = JPA가 관리할 객체

@Id = 데이터베이스 PK와 매핑 

 

 

Member.java 

package hellojpa;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table("USER")
//@Table("USER") : 쿼리가 나가는 테이블 지정
public class Member {
    @Id //PK가 뭔지 알려주는 것 Jakarta Persistence로 넣기
    private Long id;


    //만약 Column이 name이고 db가 username이면 @Column (name="username")으로 지정하면 됨
    // 그럼 인서트 쿼리가 name -> username으로 열 이름이 나감
    @Column (name="username")
    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가 관리하는 것을 알고 관리해야겠다고 생각함

 

JpaMain

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");//persistenceUnitName을 넘기라고 함 - persistence.xml의  <persistence-unit name="hello"> 부분임
        //이걸 연결하는 순간 데이터베이스랑 연결됨

        //create-entity-manger 꺼내기 - 데이터에서 커넥션 하나 받은 것임
        EntityManager em = emf.createEntityManager();

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

        Member member = new Member();

        //PK값 입력
        member.setId(1L);
        member.setName("HelloA");

        em.persist(member);

        //커밋
        tx.commit();
        emf.close();
    }
}

근데 위 코드는 하나가 문제가 생겼을 때 연쇄적으로 문제가 생길 수 있음 -> try -catch로 잡기 

 

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");//persistenceUnitName을 넘기라고 함 - persistence.xml의  <persistence-unit name="hello"> 부분임
        //이걸 연결하는 순간 데이터베이스랑 연결됨

        //create-entity-manger 꺼내기 - 데이터에서 커넥션 하나 받은 것임
        EntityManager em = emf.createEntityManager();

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

        try {
            Member member = new Member();

            //PK값 입력
            member.setId(1L);
            member.setName("HelloA");

            em.persist(member);

            //커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

아래 코드로 바꿀 수 있음

 

1. 조회 & 2. 삭제

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");//persistenceUnitName을 넘기라고 함 - persistence.xml의  <persistence-unit name="hello"> 부분임
        //이걸 연결하는 순간 데이터베이스랑 연결됨

        //create-entity-manger 꺼내기 - 데이터에서 커넥션 하나 받은 것임
        EntityManager em = emf.createEntityManager();

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

        try {
            //엔티티 매니저를 자바 컬렉션으로 생각 : 내 객체를 대신 저장해주는 것

            //Member.class 첫번째 파라메터는 엔티티 클래스 , PK가 뭐야? 1L
            //1. 조회
            Member findMember = em.find(Member.class,1L);
            System.out.println("findMember.id="+findMember.getId());
            System.out.println("findMember.name="+findMember.getName());

            //2. 삭제 - 찾은 것을 삭제
            em.remove(findMember);

            //커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

3. 수정

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");//persistenceUnitName을 넘기라고 함 - persistence.xml의  <persistence-unit name="hello"> 부분임
        //이걸 연결하는 순간 데이터베이스랑 연결됨

        //create-entity-manger 꺼내기 - 데이터에서 커넥션 하나 받은 것임
        EntityManager em = emf.createEntityManager();

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

        try {
            //엔티티 매니저를 자바 컬렉션으로 생각 : 내 객체를 대신 저장해주는 것
			
            //1. 조회
            Member findMember = em.find(Member.class,1L);

            //3. 수정
            findMember.setName("Hello,jp");

            //수정한 다음 방금 찾은 데이터는 em.persist(findMember)로 저장 안해도 됨
            //자바 컬렉션과 비슷해서

            //커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

수정한 다음 방금 찾은 데이터는 em.persist(findMember)로 저장 안해도 됨
자바 컬렉션과 비슷해서

 

조회

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

 

삭제

em.remove(findMember);

 

수정

findMember.setName("~"); → setName();은 Member에 세팅한 setter

 

객체의 값만 바뀌었는데 어떻게 DB까지 바뀌는 거지(업데이트 쿼리) ?

: 뭔가 바뀌었네 하면 JPA가 알아서 트랜잭션 커밋 전에 업데이트 쿼리를 만들어서 날리고 커밋 

 

EntityMangerFactory 

- 웹서버가 올라오는 시점에 딱 하나만 생성 됨 / DB 당 하나만 생성됨 

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

 

EntityManger

- 고객의 요청이 들어올 때마다 계속 썼다가 em.close()로 버림 

- ★ 쓰레드 간에 공유 x (사용하고 버림)

 

★ JPA의 모든 데이터 변경은 ' 트랜잭션 안에서 실행 '

(RDBMS는 데이터 변경 자체를 트랜잭션 안에서 실행하도록 되어있음) 

 

가장 단순한 조회 방법 = EntityManager.find(); (ex. em.find(Member.class, 1L);)

 

만약 나이가 18살 이상인 회원을 모두 검색하고 싶다면? (조건) - ' JPQL을 써야 함 '

 

JPQL 간단 실습

1) 전체 회원 조회 

JpaMain

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");//persistenceUnitName을 넘기라고 함 - persistence.xml의  <persistence-unit name="hello"> 부분임
        //이걸 연결하는 순간 데이터베이스랑 연결됨

        //create-entity-manger 꺼내기 - 데이터에서 커넥션 하나 받은 것임
        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();
                    //차이 : 테이블을 대상으로 짜지 않음 , 멤버 객체를 대상으로 쿼리를 하는 것
                    // 즉 select m은 m의 모든 것을 가져와!


            for(Member member : result){
                System.out.println("member.name="+member.getName());
            }

            //커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

 

기존 쿼리는 그냥 모든 열들을 나열 

jpql은 회원 엔티티를 검색한 것 

 

 

페이징도 자동으로 됨 (Limit, offset) 

List<Member> result = em.createQuery("select m from Member as m",Member.class)
        .setFirstResult(5)
        .setMaxResults(8)
        .getResultList(); //페이징 기능 : 5번부터 8개 가져와 - Limit offset이 자동으로 됨
        //차이 : 테이블을 대상으로 짜지 않음 , 멤버 객체를 대상으로 쿼리를 하는 것
        // 즉 select m은 m의 모든 것을 가져와!

 

 

JPQL : 객체를 대상으로 하는 객체 지향 쿼리 언어

 

JPA를 사용하면 엔티티 객체를 중심으로 개발

문제는 검색 커리

검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색

모든 DB 데이터를 객체로 변환해서 검색하는 것 -> 불가능

필요한 데이터만 DB에서 불러오려면 검색 조건이 포함된 SQL이 필요

 

근데!! 검색 조건은 DB에서 가져오지 않는다. (DB에 종속적이면 안됨) 

 

JPQL VS SQL

JPQL : 엔티티 객체를 대상으로 쿼리 (뭘 바꿔야할 때도 JPQL은 수정하지 않아도 된다는 장점이 있음)

SQL : 데이터베이스 테이블 대상 쿼리