본문 바로가기

멋쟁이사자처럼_부트캠프/Spring

[멋쟁이사자처럼 부트캠프 TIL 회고] 백엔드 부트캠프 13기: Java 44일차 JPA

JPA (Java Persistence API)

: Persistence_지속됨(없어지지 않고 오래 동안)

 

JPA : 인터페이스들의 묶음 = Java 애플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스.

 

인터페이스는 '규칙'과 같음. JPA는 데이터베이스를 다루는 방법에 대한 표준적인 규칙을 정의해 놓은 것.

이 규칙을 따르면 어떤 데이터베이스를 사용하든 Java 코드 변경 없이 데이터베이스를 쉽게 전환할 수 있음.

데이터, 그중에서도 특히 엔티티(Entity)의 영속성을 관리하기 위해 쓴다고 보면 됨.

JPA에서 객체에 영속성을 부여하는 주요 이유

JPA에서 객체에 영속성(Persistence) 을 부여하는 이유는 객체와 데이터베이스 간의 데이터 일관성을 유지하고, 효율적인 데이터 관리를 가능하게 하기 위함입니다.

1. 객체와 관계형 데이터베이스 간의 일관성 유지

  • JPA는 영속성 컨텍스트(Persistence Context) 를 통해 객체를 관리하며, 변경 사항을 자동으로 감지하고 데이터베이스와 동기화합니다.
  • 트랜잭션을 커밋하면, JPA는 변경된 객체들을 자동으로 반영합니다.

2. 변경 감지(Dirty Checking)

  • entityManager.find(User.class, 1L) 로 조회한 객체를 변경하면, 별도의 update SQL을 직접 실행하지 않아도 트랜잭션이 커밋될 때 자동으로 변경 사항이 반영됩니다.
  • 객체를 수정 후 entityManager.persist()를 다시 호출할 필요 없음.

데이터베이스 세계에서는 깨끗한(Clean) 상태더러운(Dirty) 상태를 구분하는 개념이 존재합니다.
1️⃣ Clean 상태 → 데이터가 영속성 컨텍스트와 DB에 저장된 내용과 동일함
2️⃣ Dirty 상태 → 데이터가 변경되었지만 아직 DB에 반영되지 않음 (수정 필요!)

🔹 JPA에서는 엔티티 객체가 처음 저장될 때는 Clean 상태입니다.
🔹 하지만, 객체의 값을 변경하면 JPA가 이를 감지하여 Dirty 상태라고 판단하고, 트랜잭션이 끝나기 전에 변경 내용을 DB에 자동으로 반영합니다.

3. 1차 캐시(First-Level Cache) 활용

  • 영속성 컨텍스트는 1차 캐시 역할을 하여, 동일한 트랜잭션 내에서 같은 객체를 여러 번 조회해도 데이터베이스에 여러 번 접근하지 않고 캐시에서 반환합니다.
User user = entityManager.find(User.class, 6L);
User user2 = entityManager.find(User.class, 6L);

동일한 id로 조회할 때, 두 객체가 동일한 인스턴스를 참조하는 것을 확인할 수 있음. (user == user2)

4. 트랜잭션 관리 용이

  • transaction.begin()으로 트랜잭션을 시작하고, 여러 개의 엔티티를 한 번에 변경한 후 transaction.commit() 하면 모든 변경 사항이 한 번에 반영됨 (원자성 보장).
  • 중간에 예외가 발생하면 rollback()을 통해 데이터 정합성을 유지할 수 있음.

5. 객체 중심 개발 가능 (SQL 직접 작성 최소화)

  • entityManager.persist(user); 를 호출하면 INSERT SQL이 자동 생성됨.
  • 개발자는 SQL을 직접 작성할 필요 없이 객체 조작을 통해 데이터베이스를 다룰 수 있음.

6. 성능 최적화 (지연 로딩, 배치 쿼리 등)

  • JPA는 지연 로딩(Lazy Loading) 을 통해 필요한 시점에만 데이터를 가져올 수 있어 불필요한 쿼리 실행을 방지함.
  • JPQL을 사용하면 복잡한 SQL 쿼리를 객체지향적으로 작성 가능.

결론

JPA에서 객체에 영속성을 부여하면 SQL 대신 객체 중심으로 데이터 관리를 할 수 있고, 성능 최적화 및 유지보수성을 높일 수 있음.
특히 변경 감지(Dirty Checking), 1차 캐시, 트랜잭션 관리 덕분에 데이터 정합성을 유지하면서도 성능을 최적화할 수 있습니다.


왜 쓰는 걸까?

 

1. 객체(Entity)와 데이터베이스(DB)의 '다리' 역할

Java는 객체 지향 프로그래밍 언어이고, 데이터베이스는 관계형 데이터베이스입니다. 둘은 데이터를 다루는 방식이 달라서 직접적인 호환이 어렵습니다. JPA는 이 둘 사이에서 '다리' 역할을 하여 객체 지향적인 방식으로 데이터베이스를 다룰 수 있도록 도와줍니다.

  → DB를 개발 프로그램에서 객체 지향적인 방식으로 DB를 다룰 수 있게 해준다.

 

2. 생산성 UP!

JPA를 사용하면 반복적인 데이터베이스 코드를 작성할 필요가 없어집니다. JPA는 '마법'처럼 객체를 데이터베이스에 자동으로 저장하고, 조회하고, 수정하고, 삭제하는 기능을 제공합니다. 개발자는 비즈니스 로직에만 집중할 수 있어 생산성이 향상됩니다.

 

3. 유지보수도 편리하게!

JPA는 데이터베이스 스키마 변경 시 코드 수정 범위를 최소화해줍니다. 객체와 테이블 간의 매핑 정보만 수정하면 되므로 유지보수가 용이해집니다.

 

JPA, 어떻게 사용하면 될까?

 

JPA는 인터페이스이므로, JPA를 실제로 사용하려면 JPA를 구현한 ORM (Object-Relational Mapping) 프레임워크가 필요합니다. 대표적인 ORM 프레임워크로는 Hibernate가 있습니다.

JPA와 Hibernate를 함께 사용하면, Java 코드를 통해 데이터베이스를 편리하게 관리할 수 있습니다.


ORM이란?

ORM(Object-Relational Mapping)은 객체 지향 프로그래밍 언어(예: Java, Python 등)에서 사용하는 객체와 관계형 데이터베이스(RDB)의 테이블 간의 데이터를 매핑하는 기술을 말합니다.

필요한 이유 : 객체 지향 프로그래밍과 관계형 데이터베이스는 데이터를 다루는 방식에 차이가 있습니다. 객체 지향 프로그래밍 언어로 작성된 애플리케이션에서 관계형 데이터베이스에 데이터를 저장하고 검색하는 과정이 복잡하고 비효율적일 수 있어서 등장하게 되었습니다.

 

ORM의 역할:

ORM은 객체와 테이블 간의 매핑을 설정하고, 객체를 통해 데이터베이스에 접근하고 조작할 수 있도록 합니다. 개발자는 SQL 쿼리를 직접 작성하지 않고도 객체 지향적인 방식으로 데이터를 처리할 수 있습니다. ORM은 다음과 같은 역할을 수행합니다.

  • 매핑: 객체와 테이블, 필드와 컬럼을 매핑합니다.
  • 변환: 객체와 데이터를 상호 변환합니다.
  • SQL 생성: 객체 기반으로 SQL 쿼리를 자동으로 생성합니다.
  • 트랜잭션 관리: 데이터베이스 트랜잭션을 관리합니다.

ORM의 장점:

  • 생산성 향상: SQL 쿼리 작성에 대한 부담을 줄여 개발 생산성을 향상시킵니다.
  • 유지보수성 향상: 객체 지향적인 방식으로 코드를 작성하여 코드의 가독성과 유지보수성을 높입니다.
  • 재사용성 향상: 매핑된 객체를 재사용하여 코드의 재사용성을 높입니다.
  • 데이터베이스 독립성: ORM을 사용하면 특정 데이터베이스에 종속되지 않고 다양한 데이터베이스를 사용할 수 있습니다.

ORM의 단점:

  • 성능 저하: ORM은 SQL 쿼리를 자동으로 생성하므로 SQL 쿼리를 직접 작성하는 것보다 성능이 저하될 수 있습니다.
  • 복잡성 증가: ORM은 매핑, 변환 등 추가적인 작업을 수행하므로 시스템의 복잡성을 증가시킬 수 있습니다.
  • 학습 곡선: ORM을 사용하기 위해서는 ORM 프레임워크에 대한 학습이 필요합니다.

대표적인 ORM 프레임워크:

  • Hibernate (Java)
  • JPA (Java Persistence API, Java 표준 ORM)* : JPQL 객체 지향 쿼리 언어를 사용.
  • MyBatis (Java)* : SQL 쿼리를 직접 작성하여 데이터베이스를 세밀하게 제어할 수 있음.
  • Django ORM (Python)
  • Active Record (Ruby on Rails)

결론:

ORM은 객체 지향 프로그래밍 언어와 관계형 데이터베이스 간의 간극을 메워주는 중요한 기술입니다. ORM을 사용하면 개발 생산성을 높이고 유지보수성을 향상시킬 수 있지만, 성능 저하 및 복잡성 증가와 같은 단점도 고려해야 합니다. ORM을 사용할 때에는 프로젝트의 특성과 요구 사항을 고려하여 적절한 ORM 프레임워크를 선택하고, ORM의 장단점을 충분히 이해하고 사용하는 것이 중요합니다.


Hibernate : Java 언어를 위한 ORM(Object-Relational Mapping) 프레임워크

자바 진영의 다양한 ORM 프레임워크 중 가장 많이 사용되는 프레임워크. Hibernate 기반으로 만들어진 ORM 기술 표준이 바로 JPA이다. 다시 말하면, JPA라는 ORM기술 표준을 구현한 것이 Hibernate이므로, JPA를 사용하려면 Hibernate를 사용하면 됨.

 

  • 간편한 사용법: 복잡한 SQL 쿼리 작성 없이 객체 조작을 통해 데이터베이스를 다룰 수 있어 개발 생산성을 향상시킵니다.
  • 유연성: 다양한 매핑 전략과 옵션을 제공하여 개발자가 원하는 방식으로 데이터베이스를 매핑할 수 있도록 합니다.
  • 확장성: 필요에 따라 Hibernate의 기능을 확장하거나 커스터마이징할 수 있습니다.

 

Hibernate의 장점:

  • 개발 생산성 향상: SQL 쿼리 작성에 대한 부담을 줄여 개발 시간을 단축시킵니다.
  • 코드 가독성 향상: 객체 지향적인 방식으로 코드를 작성하여 코드의 가독성을 높입니다.
  • 유지보수성 향상: 데이터베이스 스키마 변경 시 코드 수정 범위를 최소화하여 유지보수성을 높입니다.
  • 재사용성 향상: 매핑된 객체를 재사용하여 코드의 재사용성을 높입니다.
  • 데이터베이스 독립성: Hibernate를 사용하면 특정 데이터베이스에 종속되지 않고 다양한 데이터베이스를 사용할 수 있습니다.

Hibernate의 단점:

  • 성능 저하: Hibernate는 SQL 쿼리를 자동으로 생성하므로 SQL 쿼리를 직접 작성하는 것보다 성능이 저하될 수 있습니다.
  • 복잡성 증가: Hibernate는 매핑, 변환 등 추가적인 작업을 수행하므로 시스템의 복잡성을 증가시킬 수 있습니다.
  • 학습 곡선: Hibernate를 사용하기 위해서는 Hibernate 프레임워크에 대한 학습이 필요합니다.

Hibernate 사용 방법:

  1. Hibernate 설정: Hibernate 설정 파일(hibernate.cfg.xml)을 작성하여 데이터베이스 연결 정보, 매핑 정보 등을 설정합니다.
  2. 엔티티 클래스 정의: 데이터베이스 테이블과 매핑될 클래스를 정의하고, 어노테이션을 사용하여 매핑 정보를 설정합니다.
  3. Session 생성: Hibernate Session을 생성하여 데이터베이스 작업을 수행합니다.
  4. 트랜잭션 관리: 트랜잭션을 시작하고 커밋 또는 롤백하여 데이터의 무결성을 보장합니다.
  5. CRUD 작업: Session을 통해 객체를 생성, 조회, 수정, 삭제하는 작업을 수행합니다.

JPA의 주요 구성 요소:

  • Entity (엔티티) : 데이터베이스의 테이블에 해당하는 클래스. 이 클래스는 JPA 어노테이션을 사용하여 데이터베이스 테이블과 매핑됩니다.
  • 엔티티 매니저 (EntityManager): JPA를 통해 데이터베이스 작업을 수행하는 데 중심 역할을 하는 클래스. 엔티티의 생명 주기를 관리합니다.
  • 영속성 컨텍스트 (Persistence Context): 엔티티 인스턴스의 생명 주기를 관리하는 환경. 트랜잭션 범위 내에서 엔티티를 저장하고 관리합니다.
  • 트랜잭션: 데이터베이스 작업을 묶어주는 방법으로, 작업들이 모두 성공하거나 실패하게 보장합니다.

1️⃣ Entity (엔티티)

실제 데이터베이스의 테이블과 매핑되는 클래스
✔ @Entity 어노테이션을 사용하여 선언
✔ @Id로 기본 키(PK)를 지정해야 함

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private double salary;
}

 

2️⃣ EntityManager (엔티티 매니저)

엔티티를 데이터베이스에 저장, 조회, 수정, 삭제하는 역할
영속성 컨텍스트를 관리
✔ EntityManagerFactory에서 생성됨

 

예제 (엔티티 저장하기)

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit");
EntityManager em = emf.createEntityManager();

em.getTransaction().begin(); // 트랜잭션 시작
Employee emp = new Employee();
emp.setName("John");
emp.setSalary(5000);
em.persist(emp); // 엔티티 저장
em.getTransaction().commit(); // 트랜잭션 커밋

3️⃣ Persistence Context (영속성 컨텍스트)

JPA가 엔티티 객체를 관리하는 공간
✔ 엔티티를 영속 상태로 만들어서 변경 사항을 자동 감지 (Dirty Checking)
✔ persist(), merge(), remove(), find() 등을 통해 관리

Dirty Checking 예제

Employee emp = em.find(Employee.class, 1L); // 영속 상태
emp.setSalary(6000); // JPA가 변경 사항 자동 감지
// 트랜잭션이 커밋되면 자동으로 UPDATE SQL 실행됨

 

4️⃣ EntityManagerFactory (엔티티 매니저 팩토리)

EntityManager를 생성하는 역할
✔ 애플리케이션 실행 시 한 번만 생성됨
✔ persistence.xml에 설정된 Persistence Unit을 기반으로 동작

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit");
EntityManager em = emf.createEntityManager();

 

5️⃣ Repository (리포지토리)

Spring Data JPA에서 데이터베이스 접근을 위한 인터페이스
✔ JpaRepository를 상속하여 CRUD 메서드를 자동 제공

예제 (Spring Data JPA 사용)

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    List<Employee> findByName(String name); // 쿼리 메서드
}

 

6️⃣ JPQL (Java Persistence Query Language)

✔ SQL과 유사하지만, 테이블이 아닌 엔티티 객체를 대상으로 쿼리
✔ @Query 어노테이션을 사용하여 활용

@Query("SELECT e FROM Employee e WHERE e.salary > :salary")
List<Employee> findHighSalaryEmployees(@Param("salary") double salary);

 

📌 정리

구성 요소 역할
Entity 테이블과 매핑되는 클래스
EntityManager 엔티티 저장, 수정, 삭제, 조회 관리
Persistence Context 엔티티 객체를 관리하는 1차 캐시 역할
EntityManagerFactory EntityManager를 생성하는 팩토리
Repository Spring Data JPA에서 데이터 접근을 담당
JPQL 객체 중심의 쿼리 언어

 

 

JPA의 역할:

JPA는 다음과 같은 역할을 수행합니다.

  • 객체-관계 매핑 (ORM): Java 객체와 데이터베이스 테이블을 매핑하여 객체 지향적인 방식으로 데이터베이스를 다룰 수 있도록 합니다.
  • 데이터베이스 접근: JPA EntityManager를 통해 데이터베이스에 접근하고 데이터를 CRUD (Create, Read, Update, Delete) 작업을 수행할 수 있도록 합니다.
  • 트랜잭션 관리: EntityTransaction을 사용하여 데이터베이스 트랜잭션을 관리하고 데이터의 무결성을 보장합니다.
  • JPQL (Java Persistence Query Language): JPQL SQL과 유사한 객체 지향 쿼리 언어로, 데이터베이스에서 원하는 데이터를 검색할 수 있도록 합니다.

JPA의 구현체:

JPA는 명세이므로 실제 동작을 위해서는 구현체가 필요합니다. 대표적인 JPA 구현체로는 Hibernate, EclipseLink 등이 있습니다.

결론:

JPA는 인터페이스, 어노테이션, 클래스들의 묶음으로, Java 애플리케이션에서 관계형 데이터베이스를 효율적으로 관리하고 사용할 수 있도록 도와주는 명세입니다.


수업 : log.info(); 사용하기