컴공댕이 공부일지

[JPA] 2장 - JPA 시작 본문

study/웹개발 스터디 백엔드 EFUB 💻

[JPA] 2장 - JPA 시작

은솜솜솜 2025. 3. 16. 23:27
728x90

본 글은 도서 '자바 ORM 표준 JPA 프로그래밍'의 2장 요약 정리본입니다.

 

 

 

 


 

 

 

 

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

 

메이븐 - 라이브러리 관리해주는 도구.

pom.xml( 메이븐 설정파일)에 사용할 라이브러리 작성하면 라이브러리 자동으로 내려받아 관리

 

하이버네이트( → JPA를 실제로 구현한 대표적인 구현체 ) 핵심 라이브러리

  • hibernate-core : 하이버네이트 라이브러리 ; 가장 기본적인 ORM 기능 제공
  • hibernate-jpa-2.1-api : JPA 2.1 표준 API를 모아둔 라이브러리 ; 이러케 동작해야한다는 인터페이스 제공. 명세, 룰
  • hibernate-entitymanager : 하이버네이트가 JPA 구현체로 동작하도록 JPA 표준을 구현한 라이브러리 ;  JPA와 함께 사용할 때 필요

 

pom.xml 중 일부. dependencies : 사용할 라이브러리 지정.

<dependencies>
		<!-- JPA, 하이버네이트 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<!-- H2 데이터베이스 -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>${h2db.version}</version>
		</dependency>
	</dependencies>

groupId, artifactId, version만 적어두면,

라이브러리를 메이븐 공식 저장소에서 내려받아 라이브러리에 추가

 


 

 

📝 객체 매핑

매핑 어노테이션

어노테이션 설명
@Entity 이 클래스를 테이블과 매핑한다고 JPA에 알려줌
@Entity가 사용된 클래스=엔티티 클래스
@Table 엔티티 클래스에 매핑할 테이블 정보를 알려줌
@Id 필드를 기본 키에 매핑
@Id가 사용된 필드=식별자 필드
@Column 필드를 DB 컬럼에 매핑함
매핑 정보가 없는 필드 매핑 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑
@Column이 없어도 JPA가 자동 매핑

 

= JPA가 매핑 어노테이션을 분석해 어떤 객체가 어떤 테이블과 관계가 있는지 알아냄.

어떤 엔티티를 어떤 테이블에 저장해야 할 지 알게됨.



⚙️ persistence.xml - JPA 설정

persistence.xml 설정 - JPA 환경설정 파일 

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">

    <persistence-unit name="jpabook"> -- 연결할 DB 당 하나의 영속성 유닛을 등록하는 것이 일반적.

        <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=""/> -- sa 계정 비밀번호
            <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.id.new_generator_mappings" value="true" />

            <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>

</persistence>

 

 

 

- 사용한 속성들

JPA 표준 속성 (특정 구현체에 종속되지 않음)

  • javax.persistence.jdbc.driver : JDBC 드라이버
  • javax.persistence.jdbc.user : 데이터베이스 접속 아이디
  • javax.persistence.jdbc.password : 데이터베이스 접속 비밀번호
  • javax.persistence.jdbc.url : 데이터베이스 접속 URL

 

하이버네이트 속성

  • hibernate.dialect : 데이터베이스 방언 설정
  • hibernate.show_sql : 하이버네이트가 실행한 SQL 출력
  • hibernate.format_sql : 하이버네이트가 실행한 SQL을 보기 좋게 정렬
  • hibernate.use_sql_comments : 쿼리를 출력할 때 주석도 함께 출력
  • hibernate.id.new_generator_mappings : JPA 표준에 맞춘 새로운 키 생성 전략 사용

 

 


 

 

 

🗣️ 데이터베이스 방언

 SQL 표준을 지키지 않거나 특정 DB만의 고유한 기능

 

  • 대부분의 JPA 구현체들은 다양한 데이터베이스 방언 클래스를 제공
    특정 DB에 종속되는 기능을 사용한 경우에도, DB 교체 수월하도록. DB와 독립적이도록 !
  • 개발자는 JPA가 제공하는 표준 문법에 맞추어 JPA를 사용하면 되고, 특정 데이터베이스에 의존적인 SQL은 데이터베이스 방언이 알아서 처리해줌
    • 데이터베이스가 변경되면 데이터베이스 방언만 교체하면 됨

 

  • 하이버네이트가 제공하는 데이터베이스 방언
    • H2 : org.hibernate.dialect.H2Dialect
    • 오라클 10g : org.hibernate.dialect.Oracle10gDialect
    • MySQL : org.hibernate.dialect.MySQL5InnoDBDialect

 

 


 

 

package jpabook.start;

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

/**
 * @author holyeye
 */
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(2);

        //등록
        em.persist(member);

        //수정
        member.setAge(20);

        //한 건 조회
        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);

    }
}

 


 

1️⃣ 엔티티 매니저 설정

- 앤티티 매니저 팩토리  ; 엔티티 매니저 생성하는 공장

persistence.xml의 설정 정보 읽어, 영속성 유닛을 찾아 엔티티 매니저 팩토리 생성

데이터베이스 연결 풀을 관리하므로 무분별하게 생성하면 성능 저하가 발생

한 번만 생성해서 공유해 사용할 것 !

어플리케이션 종료 시 엔티티 매니저 팩토리도 종료 emf.close()

 

- 앤티티 매니저 ; JPA 동작시키기 위한 기본 객체

실제 DB와 상호작용하는 객체 ▶ 데이터베이스 작업(저장, 수정, 삭제, 조회 등)을 수행하는 객체 

→  DB 커넥션과 밀접한 관계가 있으므로, 각 스레드에서 독립적으로 사용.

→ 스레드 간에 공유X 재사용X

사용이 끝난 엔티티 매니저는 반드시 종료할 것. em.close()

 

 


 

2️⃣ *트랜잭션 관리

*트랜잭션 : 데이터베이스에서 일련의 작업을 하나의 단위로 묶어 처리하는 것

트랜잭션 안에서 수행된 모든 작업은 모두 성공해야만 데이터베이스에 반영되고,
하나라도 실패 시 전체 작업이 취소됨.
→ 데이터의 일관성을 보장하고, 원자성을 유지함.

 

JPA에서 데이터 변경 작업은 항상 트랜잭션 안에서 수행해야 함.
엔티티 매니저에서 트랜잭션 API 받아와서,

EntityTransaction tx = em.getTransaction();

 

commit( 비지니스 로직 정상 동작)과 rollback( 예외 발생) 등을 사용함.

 

 


 

 

3️⃣ 비즈니스 로직

 

등록 : persist(entity)

//등록
em.persist(member);

 


수정 : update() 메서드 없음, 엔티티 속성 직접 변경

//수정
member.setAge(20);

 


삭제 : remove(entity)

//삭제
em.remove(member);

 

 

조회 : find(entityClass, primaryKey), 엔티티(실제 데이터 ex. member)의 클래스 타입과 기본키로 조회

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

        //목록 조회 - JPLQ 쿼리로 Member 엔티티 객체 목록 반환
        List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
        System.out.println("members.size=" + members.size());

 

 


 

 

⭐ JPQL (Java Persistence Query Language)

JPA에서 사용되는 객체 지향 쿼리 언어

DB의 테이블 대신 엔티티 객체를 기반으로 쿼리를 작성

 

 

JPA엔티티 객체를 중심으로 설계

검색 시 데이터베이스 테이블이 아니라 엔티티 객체를 대상으로 쿼리해야 함

모든 데이터를 애플리케이션에 불러와 엔티티로 변환한 후 검색하는 것은 불가능 !

JPQL은 객체 지향 쿼리 언어

SQL과 비슷. 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 쿼리

그래서 JPQL은 DB의 테이블을 전혀 알지 못한다 !

 

SQL은 데이터베이스 테이블을 대상으로 직접 쿼리하는 방식이다.

 

 

위의 비지니스 로직에도 JPQL 쿼리가 쓰였다.

아직은 익숙하지 않아서.. 아래는 좀 더 찾아 본 JPQL 쿼리 예시들

JPQL 쿼리 예시 🥸

 


 

 

+ JPA의 이점

 

1. 객체 지향적인 데이터 관리

  • JPA는 데이터베이스 테이블을 자바 객체(엔티티)로 매핑하여 객체 지향 프로그래밍 패러다임을 따릅니다.
  • JPQL은 SQL과 유사하지만, 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 쿼리하므로 객체 지향적인 데이터 관리가 가능합니다.

2. 생산성 향상

  • JPA는 복잡한 데이터베이스 작업을 추상화하여 개발자가 비즈니스 로직에 집중할 수 있도록 도와줍니다.
    em.remove(member);  ▶  JPA가 SQL 생성해 실행. DELETE FROM MEMBER WHERE ID = "id1";
  • JPQL은 SQL보다 간결하고 명확한 쿼리 작성을 가능하게 하여 개발 생산성을 향상시킵니다.

3. 유지보수성 향상

  • JPA는 데이터베이스 스키마 변경 시 엔티티 매핑만 수정하면 되므로 코드 수정 범위를 최소화합니다.
  • JPQL은 데이터베이스에 독립적이므로 데이터베이스 종류가 변경되더라도 쿼리를 수정할 필요가 없습니다.

4. 데이터베이스 독립성

  • JPA는 다양한 데이터베이스 시스템을 지원하므로 특정 데이터베이스에 종속되지 않습니다.
  • JPQL은 JPA 구현체에 의해 각 데이터베이스에 맞는 SQL로 변환되므로 데이터베이스 종류에 상관없이 동일한 JPQL 쿼리를 사용할 수 있습니다.

5. 성능 최적화

  • JPA는 영속성 컨텍스트, 1차 캐시, 지연 로딩 등 다양한 성능 최적화 기능을 제공합니다.
  • JPQL은 필요한 데이터만 조회하도록 쿼리를 최적화하여 데이터베이스 성능을 향상시킬 수 있습니다.

6. 코드 가독성 향상

  • JPQL은 SQL보다 간결하고 명확한 쿼리를 작성할 수 있어 코드 가독성을 높입니다.
  • JPQL은 엔티티 간의 관계를 활용하여 복잡한 쿼리를 쉽게 작성할 수 있습니다.

7. 타입 안전성

  • JPQL은 컴파일 시점에 쿼리 오류를 검출하여 런타임 오류를 방지합니다.
  • JPQL은 엔티티 타입을 명시하므로 타입 안전성을 보장합니다.

 

2장 요약

 

 JPA 사용 개발 환경 설정 진행.

객체 하나를 테이블에 등록/수정/삭제/조회 하는 애플리케이션 제작

JPA가 반복적인 JDBC API와 결과 값 매핑 처리 -> 코드 줄고, sql 작성할 필요 x

 

728x90