Database/JPA / / 2024. 9. 10. 11:42

JPA 엔티티 관리 메서드

JPA에서 엔티티 매니저(EntityManager)를 통해 사용할 수 있는 메서드들은 다양한 상태와 작업을 지원해. 각 메서드는 엔티티를 영속성 컨텍스트와 데이터베이스 사이에서 어떻게 관리하고 처리할지를 정의하는 중요한 기능을 제공해. 주요 메서드들을 설명하자면:

 

1. persist(Object entity):

엔티티를 영속성 컨텍스트에 저장하는 메서드. 이 메서드를 호출하면 엔티티가 영속성 컨텍스트에 저장되고, 이후에 데이터베이스에 반영될 준비가 돼.

그러나 쿼리가 즉시 실행되는 건 아니고, flush() 또는 트랜잭션이 커밋될 때 쿼리가 실행돼.

2. flush():

영속성 컨텍스트에 있는 엔티티들의 변경 사항을 즉시 데이터베이스에 반영하는 메서드. 즉, 영속성 컨텍스트에서 관리하는 엔티티들에 대해 SQL 쿼리가 실행돼.

3. find(Class<T> entityClass, Object primaryKey):

데이터베이스에서 엔티티를 조회할 때 사용해. 주어진 식별자(primary key)를 통해 엔티티를 찾아오고, 영속성 컨텍스트에 로드해. 이미 영속성 컨텍스트에 해당 엔티티가 있으면 데이터베이스 쿼리를 실행하지 않고 컨텍스트에서 반환해.

4. merge(Object entity):

준영속 상태(Detached)인 엔티티를 다시 영속성 컨텍스트로 병합하는 메서드야. 즉, 이미 존재하는 엔티티를 갱신하려는 경우에 사용해.

이 메서드는 새로운 인스턴스를 반환하며, 반환된 인스턴스가 영속성 컨텍스트에 의해 관리돼.

5. remove(Object entity):

영속성 컨텍스트에서 관리 중인 엔티티를 삭제할 때 사용해. 엔티티를 삭제한 후 flush() 또는 트랜잭션 커밋 시 데이터베이스에서 실제로 삭제 작업이 실행돼.

6. detach(Object entity):

특정 엔티티를 **영속성 컨텍스트에서 분리(Detached)**시키는 메서드야. 분리된 엔티티는 더 이상 JPA에 의해 관리되지 않고, 영속성 컨텍스트에 변경사항이 반영되지 않아.

7. clear():

영속성 컨텍스트의 모든 엔티티를 초기화하여 분리(Detached)시키는 메서드. 즉, 현재 관리 중인 모든 엔티티에 대한 변경 사항을 무효화하고, 더 이상 관리하지 않아.

8. refresh(Object entity):

영속성 컨텍스트에 있는 엔티티를 데이터베이스의 최신 상태로 갱신해. 이미 영속성 컨텍스트에 저장된 엔티티가 있지만, 데이터베이스에서 해당 엔티티의 변경된 내용을 가져오고 싶을 때 사용해.

9. getReference(Class<T> entityClass, Object primaryKey):

**지연 로딩(Lazy Loading)**을 지원하는 메서드. 실제로 데이터베이스 쿼리를 실행하지 않고, 프록시 객체만을 반환해. 나중에 해당 엔티티가 실제로 사용될 때 쿼리가 실행돼.

10. lock(Object entity, LockModeType lockMode):

 

영속성 컨텍스트에서 관리 중인 엔티티에 대해 락(Lock)을 설정할 때 사용해. 동시성 문제를 방지하기 위해 비관적(Pessimistic) 또는 낙관적(Optimistic) 락을 설정할 수 있어.

 

메서드들의 역할 요약:

 

persist(): 엔티티를 영속 상태로 만들어 JPA가 관리하게 함.

flush(): 영속성 컨텍스트의 변경 사항을 즉시 데이터베이스에 반영.

find(): 데이터베이스에서 엔티티를 조회.

merge(): 준영속 상태의 엔티티를 영속성 컨텍스트로 병합.

remove(): 엔티티를 삭제.

detach(): 엔티티를 영속성 컨텍스트에서 분리.

clear(): 영속성 컨텍스트를 완전히 비움.

refresh(): 엔티티를 데이터베이스의 최신 상태로 갱신.

getReference(): 지연 로딩을 위한 프록시 객체를 반환.

lock(): 엔티티에 락을 설정해 동시성 문제를 해결.

 

이 메서드들을 적절하게 사용하면, JPA를 통한 데이터베이스 작업에서 다양한 상태와 상황을 처리할 수 있어.

 

JPQL(Java Persistence Query Language)은 JPA에서 제공하는 객체지향 쿼리 언어로, 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 쿼리를 작성하는 데 사용돼. JPQL은 SQL과 유사하지만, 실제로는 자바 객체 모델을 대상으로 동작하는 쿼리 언어야. 즉, 테이블과 컬럼 대신 엔티티 클래스와 그 속성에 대해 쿼리를 작성하지.

 

JPQL의 주요 특징

 

1. 객체지향적 쿼리: JPQL은 객체를 대상으로 쿼리하므로, 데이터베이스 테이블 대신 엔티티 클래스와 필드를 대상으로 쿼리를 작성해. 예를 들어, SELECT u FROM User uUser라는 엔티티 객체의 모든 데이터를 조회하는 JPQL 구문이야.

2. 엔티티 간의 관계 처리: JPQL은 객체 간의 관계(예: 1:N, N:M 등)를 자연스럽게 처리할 수 있어. SQL에서는 복잡한 조인 구문이 필요하지만, JPQL은 객체지향적인 접근 방식을 사용해 간단하게 처리할 수 있어.

3. 플랫폼 독립적: JPQL은 특정 데이터베이스에 종속되지 않아, 데이터베이스의 종류와 상관없이 동일한 쿼리를 사용할 수 있어. 이는 JPA가 제공하는 추상화 기능 덕분이야.

4. 동적 쿼리: JPQL은 런타임에 동적으로 생성할 수도 있어. 이를 통해 다양한 조건에 따라 쿼리를 유연하게 생성할 수 있어.

 

JPQL 예시

String jpql = "SELECT u FROM User u WHERE u.age > 20";
List<User> users = em.createQuery(jpql, User.class).getResultList();

 

위 코드는 User 엔티티에서 age가 20 이상인 사용자 목록을 조회하는 JPQL 구문이야. 여기서 중요한 건, User는 데이터베이스의 테이블이 아닌 JPA에서 관리하는 엔티티라는 점이야.

 

JPQL과 SQL의 차이점

 

JPQL은 객체와 그 속성에 대해 쿼리를 작성하는 반면, SQL은 데이터베이스 테이블과 컬럼을 대상으로 쿼리해.

JPQL은 자바 엔티티 클래스와 연관된 모든 데이터베이스를 동일한 방식으로 접근하지만, SQL은 특정 데이터베이스에 종속적이기 때문에 데이터베이스마다 문법이 조금씩 달라질 수 있어.

 

결론적으로, JPQL은 SQL보다 더 객체지향적이고 유연한 쿼리 언어야. JPA를 사용해 데이터베이스를 관리할 때, 데이터베이스에 대한 세부 사항을 추상화하여 더 일관성 있는 코드를 작성할 수 있게 도와줘.

 

아래는 main 함수에서 Member 엔티티를 H2에 저장하는 흐름입니다.

package com.jinsu.jpaexs;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class Main {

    public static void main(String[] args) {
        
        // EntityManagerFactory 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
        EntityManager em = emf.createEntityManager();
        
        // 트랜잭션 시작
        EntityTransaction tx = em.getTransaction();
        
        try {
            tx.begin(); // 트랜잭션 시작
            
            // 새로운 Member 엔티티 생성
            Member newMember = new Member();
            newMember.setId(1L); // ID는 고유해야 함
            newMember.setUsername("Jinsu");
            newMember.setAge(27);
            
            // persist() 메서드를 사용해 엔티티 영속화 (데이터베이스에 저장 준비)
            em.persist(newMember);
            
            // 트랜잭션 커밋 (데이터베이스에 반영)
            tx.commit();
            
            System.out.println("Member가 데이터베이스에 저장되었습니다.");
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback(); // 에러 발생 시 트랜잭션 롤백
        } finally {
            em.close();  // EntityManager 종료
            emf.close(); // EntityManagerFactory 종료
        }
    }
}

 

JPA를 이용해 CRUD(Create, Read, Update, Delete) 기능을 구현하는 코드야. EntityManager를 사용해서 데이터를 추가하고, 조회하고, 수정하고, 삭제하는 방법을 보여줄게.

 

1. Create (생성)

public static void create(EntityManager em, Long id, String name, Integer age) {
    Member member = new Member();
    member.setId(id);
    member.setUsername(name);
    member.setAge(age);
    em.persist(member); // 새로운 멤버 엔티티를 영속성 컨텍스트에 저장 (생성)
    System.out.println("Member created: " + member);
}

 

2. Read (조회)

public static Member read(EntityManager em, Long id) {
    Member member = em.find(Member.class, id); // 엔티티를 ID로 조회
    if (member != null) {
        System.out.println("Member found: " + member);
    } else {
        System.out.println("No member found with ID: " + id);
    }
    return member;
}

 

3. Update (수정)

public static void update(EntityManager em, Long id, String newName, Integer newAge) {
    Member member = em.find(Member.class, id); // 수정할 엔티티 조회
    if (member != null) {
        member.setUsername(newName); // 이름 수정
        member.setAge(newAge); // 나이 수정
        em.merge(member); // 엔티티 병합
        System.out.println("Member updated: " + member);
    } else {
        System.out.println("No member found with ID: " + id);
    }
}

 

4. Delete (삭제)

public static void delete(EntityManager em, Long id) {
    Member member = em.find(Member.class, id); // 삭제할 엔티티 조회
    if (member != null) {
        em.remove(member); // 엔티티 삭제
        System.out.println("Member deleted: " + member);
    } else {
        System.out.println("No member found with ID: " + id);
    }
}

 

Main 메서드에서 CRUD 호출 예시:

public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    
    try {
        tx.begin();
        
        // Create
        create(em, 1L, "Jinsu", 27);

        // Read
        Member member = read(em, 1L);

        // Update
        update(em, 1L, "Taehun", 30);

        // Delete
        delete(em, 1L);
        
        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        em.close();
        emf.close();
    }
}

 

이 코드를 실행하면 create(), read(), update(), delete() 메서드를 통해 Member 엔티티에 대한 CRUD 작업을 수행할 수 있어. 각 메서드는 EntityManager를 통해 데이터베이스와 상호작용하게 돼.

 

JPQL (Java Persistence Query Language)은 JPA (Java Persistence API)에서 사용하는 객체 지향 쿼리 언어야. SQL과 유사하지만, JPQL은 **테이블이 아닌 객체(Entity)**를 대상으로 쿼리를 작성하는 게 특징이야. 즉, JPQL은 데이터베이스 테이블이 아닌 JPA 엔티티 모델을 기반으로 동작해.

 

JPQL의 기본 개념:

 

1. 객체 지향 쿼리: JPQL은 테이블이 아닌 엔티티를 대상으로 쿼리를 실행해. 예를 들어, SQL에서 테이블을 대상으로 쿼리하지만, JPQL은 클래스와 필드를 대상으로 쿼리를 작성해. 즉, 테이블이 아닌 객체의 속성으로 필드를 조회하지.

2. JPA 표준 쿼리 언어: JPQL은 JPA의 표준 쿼리 언어로, 데이터베이스 독립적인 쿼리를 작성할 수 있어.

3. 데이터베이스에 종속적이지 않음: JPQL은 특정 데이터베이스에 종속되지 않고, JPA 구현체가 자동으로 데이터베이스에 맞는 SQL로 변환해 줘.

 

코드 설명:

TypedQuery<Member> query = em.createQuery("select m from Member m", Member.class);
List<Member> members = query.getResultList();

 

em.createQuery(): JPQL 쿼리를 실행하려면 EntityManagercreateQuery() 메서드를 사용해. 이 메서드는 JPQL 쿼리를 받아서 실행 준비를 해.

em.createQuery("select m from Member m", Member.class);

 

“select m from Member m”: 이 부분은 JPQL 쿼리야.

**select m**은 Member 엔티티의 모든 필드를 선택한다는 의미고,

**from Member m**은 Member 엔티티를 대상으로 쿼리를 실행한다는 의미야. 여기서 m은 Member 엔티티의 별칭(alias)이야. 이 부분이 SQL과 비슷해 보여도, 사실 Member 엔티티 클래스를 대상으로 하고 있어.

 

TypedQuery<Member>: JPQL 쿼리를 실행하는 객체로, 이 쿼리는 Member 엔티티 리스트를 반환해.

query.getResultList(): JPQL 쿼리를 실행하고 결과를 **List**로 반환해. 여기서 JPQL은 Member 엔티티에 해당하는 데이터를 데이터베이스에서 조회한 후, 그 데이터를 Member 객체로 변환해서 리스트에 담아 반환해.

 

주요 JPQL 기능:

 

1. SELECT 쿼리: 객체를 대상으로 데이터를 조회하는 가장 기본적인 쿼리로, 클래스와 그 필드를 선택해 데이터를 가져올 수 있어.

2. JOIN: 여러 엔티티 간의 연관 관계를 기반으로 데이터를 조회할 수 있어.

SELECT o FROM Order o JOIN o.customer c WHERE c.name = 'John'

 

3. 조건문: WHERE 절을 사용해 조건을 추가할 수 있어.

SELECT m FROM Member m WHERE m.age > 20

 

4. 정렬 및 그룹핑: JPQL은 ORDER BY, GROUP BY와 같은 SQL 문법을 활용할 수 있어.

SELECT m FROM Member m ORDER BY m.age DESC

 

요약:

 

JPQL은 JPA를 사용하는 자바 애플리케이션에서 객체 중심으로 데이터베이스와 상호작용할 수 있게 해주는 쿼리 언어야. 이 언어를 사용하면 SQL을 사용하지 않고도 엔티티 기반으로 데이터베이스와 통신할 수 있지.

 

Tip💡

1. JPA에서의 flush

 

**flush()**는 영속성 컨텍스트에서 관리되고 있는 엔티티의 변경 사항을 데이터베이스에 반영하는 역할을 해. 즉, 메모리에 있는 엔티티들의 변경 사항을 즉시 데이터베이스에 반영해주는 거지.

트랜잭션 내에서 flush()는 SQL 쿼리를 강제로 실행하여 변경 사항을 디스크(데이터베이스)에 반영하게 해, 하지만 이때 트랜잭션이 커밋되지 않았으면, 변경 사항은 아직 완전히 확정된 건 아니야.

 

2. Git에서의 push

 

push는 로컬 저장소에서 작업한 변경 사항(커밋)을 원격 저장소(서버)로 전송하는 명령어야.

로컬에서 완료한 작업 내용을 원격 저장소에 공유해서 다른 개발자들이 해당 변경 사항을 볼 수 있게 하거나, 협업을 가능하게 해.

 

비교

 

**flush()**는 JPA에서 메모리 내에서 변경된 데이터를 데이터베이스에 임시로 반영하지만, 트랜잭션이 커밋되지 않으면 실제로 저장되지 않을 수 있어.

반면, push는 로컬에서의 변경 사항을 최종적으로 원격 저장소에 반영해서, 공유하거나 협업하는 용도로 사용돼.

 

즉, flush()는 데이터베이스에 데이터를 임시로 반영하는 것이라면, push는 Git에서 데이터를 최종적으로 서버에 반영하는 기능이야.

 

1. JPA에서의 persist

 

persist()는 엔티티를 **영속성 컨텍스트(Persistence Context)**에 저장하는 기능이야. 이 상태에서는 엔티티가 메모리에 저장되어 있고, 아직 데이터베이스에 확정되지 않은 상태야.

즉, persist()는 엔티티를 관리 대상으로 등록해 데이터베이스에 반영될 준비를 하는 단계지.

 

2. Git에서의 add

 

git add는 작업 중인 파일을 **스테이징 영역(stage)**에 추가하는 기능이야. 파일이 스테이징 영역에 있으면, 이후에 commit을 통해 변경 사항을 저장할 준비를 하게 돼.

이때 add는 파일을 최종적으로 커밋한 건 아니고, 커밋될 준비를 하는 상태야.

 

비교

 

**persist()**는 엔티티를 영속성 컨텍스트에 추가해 데이터베이스에 반영될 준비를 하는 단계고, add는 변경 사항을 스테이징 영역에 추가해 커밋될 준비를 하는 단계라는 점에서 유사해.

둘 다 최종 상태가 아니라, 이후에 커밋(commit) 또는 트랜잭션 커밋이 되어야 데이터베이스나 원격 저장소에 반영돼.

 

따라서, persist()는 엔티티를 “추적”하기 위한 첫 단계라면, add는 파일을 커밋할 준비를 하는 단계로, 둘은 “준비”라는 면에서 비슷해.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유