Note-Taking / / 2024. 9. 20. 09:49

JPA 어노테이션의 핵심 정리

1. @Entity

 

설명: JPA에서 관리하는 엔티티 클래스임을 선언. 이 클래스는 데이터베이스의 테이블에 대응돼.

사용 예시:

@Entity
public class Member {
    @Id
    private Long id;
    private String name;
}

 

2. @Id

 

설명: 해당 필드를 **기본 키(Primary Key)**로 지정.

사용 예시:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

 

3. @GeneratedValue

 

설명: 기본 키 생성 전략을 지정. AUTO, IDENTITY, SEQUENCE, TABLE이 사용될 수 있어.

AUTO: JPA가 자동으로 선택

IDENTITY: 데이터베이스에 의존하여 자동 증가

SEQUENCE: 시퀀스 객체를 사용해 키 생성

TABLE: 별도의 키 생성용 테이블 사용

사용 예시:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

 

4. @Column

 

설명: 엔티티 클래스의 필드를 데이터베이스의 **열(Column)**에 매핑. 디폴트로 필드 이름이 데이터베이스의 컬럼 이름과 같지만, 커스터마이징 가능.

속성: name, nullable, length, unique

사용 예시:

@Column(name = "user_name", nullable = false, length = 100)
private String name;

 

5. @Table

 

설명: 엔티티와 연결된 데이터베이스 테이블을 지정. 기본적으로 클래스 이름이 테이블 이름으로 사용되지만, 변경할 수 있어.

사용 예시:

@Entity
@Table(name = "members")
public class Member {
    @Id
    private Long id;
}

 

6. @OneToOne

 

설명: 두 엔티티 간의 일대일 관계를 매핑. 하나의 엔티티가 다른 하나의 엔티티와만 연결될 때 사용.

사용 예시:

@OneToOne
@JoinColumn(name = "locker_id")
private Locker locker;

 

7. @ManyToOne

 

설명: 다대일 관계를 매핑. 여러 엔티티가 하나의 엔티티에 연결될 때 사용.

사용 예시:

@ManyToOne
@JoinColumn(name = "team_id")
private Team team;

 

8. @OneToMany

 

설명: 일대다 관계를 매핑. 하나의 엔티티가 여러 엔티티와 연결될 때 사용. 주로 @ManyToOne과 반대 방향 관계에서 사용.

사용 예시:

@OneToMany(mappedBy = "team")
private List<Member> members;

 

9. @ManyToMany

 

설명: 다대다 관계를 매핑. 여러 엔티티가 서로 여러 개의 엔티티와 연결될 때 사용. 중간 테이블을 필요로 함.

사용 예시:

@ManyToMany
@JoinTable(name = "member_product", joinColumns = @JoinColumn(name = "member_id"), inverseJoinColumns = @JoinColumn(name = "product_id"))
private List<Product> products;

 

10. @JoinColumn

 

설명: 외래 키(Foreign Key)를 매핑할 때 사용. 관계를 맺은 테이블의 외래 키 정보를 정의.

사용 예시:

@ManyToOne
@JoinColumn(name = "team_id")
private Team team;

 

11. @Embeddable

 

설명: 값 타입을 정의하는 클래스에 사용. 객체의 여러 속성을 하나의 컬럼에 매핑할 때.

사용 예시:

@Embeddable
public class Address {
    private String city;
    private String street;
}

 

12. @Embedded

 

설명: 다른 클래스에서 @Embeddable로 정의된 값 타입을 포함할 때 사용.

사용 예시:

@Embedded
private Address address;

 

13. @ElementCollection

 

설명: 컬렉션 값 타입을 저장할 때 사용. 엔티티의 컬렉션을 데이터베이스에 저장하는데, 별도의 테이블을 만들어 관리.

사용 예시:

@ElementCollection
@CollectionTable(name = "favorite_foods", joinColumns = @JoinColumn(name = "member_id"))
private Set<String> favoriteFoods = new HashSet<>();

 

14. @MappedSuperclass

 

설명: 공통 속성을 가진 클래스를 상속받는 여러 엔티티 클래스에서 공통으로 사용될 필드를 정의할 때 사용. 데이터베이스에 매핑되지 않음.

사용 예시:

@MappedSuperclass
public abstract class BaseEntity {
    private String createdBy;
    private LocalDateTime createdDate;
}

 

15. @Inheritance

 

설명: 상속 관계를 매핑할 때 사용. SINGLE_TABLE, JOINED, TABLE_PER_CLASS 전략을 선택할 수 있어.

사용 예시:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
public class Item {
    @Id
    @GeneratedValue
    private Long id;
}

 

16. @Version

 

설명: 낙관적 락(Optimistic Lock)을 위한 버전 관리 필드에 사용. 데이터베이스 테이블에서 해당 엔티티의 버전 정보를 관리함.

사용 예시:

@Version
private Integer version;

 

17. @PrePersist, @PostPersist, @PreUpdate, @PostUpdate

 

설명: 엔티티의 생명주기 이벤트를 처리하는 메서드에 사용. 엔티티가 저장되거나 수정될 때 특정 메서드를 실행할 수 있게 해.

사용 예시:

@PrePersist
public void prePersist() {
    createdDate = LocalDateTime.now();
}

 

18. @Query

 

설명: JPQL 또는 네이티브 SQL을 사용해 직접 쿼리를 작성할 때 사용.

사용 예시:

@Query("SELECT m FROM Member m WHERE m.name = :name")
List<Member> findByName(@Param("name") String name);

 

Tip💡

JPA에서 자주 사용하는 어노테이션들을 잘 이해하고 있다면, JPA의 기본적인 개념과 기능에 대해 충분히 숙지한 상태라고 할 수 있어. 하지만, JPA를 “잘 안다”고 말하기 위해서는 단순히 어노테이션의 사용법만이 아니라 다양한 상황에서 JPA를 활용하는 실전 경험최적화 방법도 중요해. 몇 가지 더 깊이 알아야 할 사항을 덧붙이자면:

 

1. JPA 기본 동작 원리 이해

 

영속성 컨텍스트(Persistence Context): 엔티티가 어떻게 영속성 컨텍스트에 의해 관리되고, 데이터베이스와 동기화되는지 이해해야 해.

플러시(Flush)와 커밋(Commit): JPA에서 데이터 변경이 언제, 어떻게 DB에 반영되는지, flush()commit()의 차이점을 알 필요가 있어.

트랜잭션 관리: 트랜잭션의 범위와 JPA가 트랜잭션을 어떻게 처리하는지 이해하는 것이 필수야.

 

2. 고급 매핑 전략

 

상속 매핑(@Inheritance)의 세 가지 전략 (SINGLE_TABLE, JOINED, TABLE_PER_CLASS)을 언제, 어떻게 사용하는지 이해해야 해.

복합 키 매핑과 그에 따른 식별 관계와 비식별 관계의 차이점에 대한 이해도 필요해.

 

3. 성능 최적화와 문제 해결

 

N+1 문제: 연관된 엔티티를 조회할 때 발생할 수 있는 성능 문제를 해결하기 위해 **지연 로딩(LAZY Loading)**과 **즉시 로딩(EAGER Loading)**의 차이, 그리고 이를 어떻게 설정해야 성능이 개선되는지 알아야 해.

쿼리 최적화: JPQL과 네이티브 쿼리 작성법을 알고, 복잡한 조건 쿼리와 성능을 개선하기 위한 페치 조인(Fetch Join) 같은 기법을 사용할 수 있어야 해.

 

4. 데이터베이스와의 동기화

 

벌크 연산배치 처리: 대량의 데이터를 처리할 때 성능을 높이기 위한 벌크 연산의 중요성.

2차 캐시와 1차 캐시: JPA의 캐시 전략을 이해하고, 어떻게 데이터베이스와 캐시를 동기화하는지 알아야 해.

 

5. JPA와 스프링 데이터 JPA

 

스프링 부트 프로젝트에서 JPA를 사용할 때, Spring Data JPA를 이용한 Repository 패턴과 함께 어떻게 동작하는지, 특히 자동으로 쿼리가 생성되는 원리와 복잡한 조건을 처리하는 방법을 이해해야 해.

 

결론:

 

어노테이션의 이해는 JPA를 사용하는 데 매우 중요한 첫걸음이야. 하지만 이를 바탕으로 실제 프로젝트에서 성능 문제를 해결하고, 복잡한 엔티티 관계를 매핑하고, 쿼리 최적화 등을 할 수 있어야 “JPA를 잘 안다”고 말할 수 있어. JPA는 단순 CRUD 이상으로 엔티티 간의 관계 설정, 효율적인 트랜잭션 관리, 성능 튜닝이 중요한 만큼, 실전 프로젝트에서 이를 어떻게 활용하는지가 매우 중요해.

 


 

JPA에서 사용하는 어노테이션들을 실제로 main 메서드에서 활용하는 방법을 쉽게 설명할게. 이를 통해 기본적인 CRUD (Create, Read, Update, Delete) 작업을 어떻게 수행하는지 예제를 만들어 보자. 이 과정에서 JPA의 영속성 컨텍스트와 트랜잭션 처리 방식도 함께 익히게 될 거야.

 

1. 기본적인 CRUD 예제

 

JPA 어노테이션들을 사용해 회원(Member) 엔티티와 관련된 기본적인 데이터베이스 작업을 처리하는 방법을 보여줄게. 아래 예제에서는 @Entity, @Id, @GeneratedValue, @Column, @OneToMany 등을 어떻게 사용할 수 있는지 볼 수 있어.

 

회원(Member) 엔티티

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<FavoriteFood> favoriteFoods = new HashSet<>();

    // Getters and Setters
    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;
    }

    public Set<FavoriteFood> getFavoriteFoods() {
        return favoriteFoods;
    }

    public void setFavoriteFoods(Set<FavoriteFood> favoriteFoods) {
        this.favoriteFoods = favoriteFoods;
    }
}

 

좋아하는 음식(FavoriteFood) 엔티티

import javax.persistence.*;

@Entity
public class FavoriteFood {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String foodName;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFoodName() {
        return foodName;
    }

    public void setFoodName(String foodName) {
        this.foodName = foodName;
    }

    public Member getMember() {
        return member;
    }

    public void setMember(Member member) {
        this.member = member;
    }
}

 

2. 메인 클래스에서 CRUD 작업 수행

 

이제 main 메서드에서 JPA를 사용하여 회원을 추가하고, 수정하고, 조회하고, 삭제하는 예제를 작성해볼게. 여기서는 EntityManager트랜잭션 관리에 중점을 둬.

 

Main 클래스

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

public class Main {

    private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");

    public static void main(String[] args) {
        // Create EntityManager
        EntityManager em = emf.createEntityManager();

        // Start transaction
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();

            // 1. Create new member and favorite foods (Create)
            Long memberId = createMemberWithFavoriteFood(em);

            // 2. Retrieve and print member info (Read)
            printMemberInfo(em, memberId);

            // 3. Update member name (Update)
            updateMemberName(em, memberId, "New Member Name");

            // 4. Delete member (Delete)
            deleteMember(em, memberId);

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

    // Create a new member with favorite foods
    public static Long createMemberWithFavoriteFood(EntityManager em) {
        Member member = new Member();
        member.setName("John Doe");

        FavoriteFood pizza = new FavoriteFood();
        pizza.setFoodName("Pizza");
        pizza.setMember(member);

        FavoriteFood sushi = new FavoriteFood();
        sushi.setFoodName("Sushi");
        sushi.setMember(member);

        member.getFavoriteFoods().add(pizza);
        member.getFavoriteFoods().add(sushi);

        // Persist member (automatically persists favorite foods due to CascadeType.ALL)
        em.persist(member);

        return member.getId();
    }

    // Retrieve and print member info
    public static void printMemberInfo(EntityManager em, Long memberId) {
        Member member = em.find(Member.class, memberId);
        if (member != null) {
            System.out.println("Member ID: " + member.getId());
            System.out.println("Member Name: " + member.getName());
            System.out.println("Favorite Foods:");
            for (FavoriteFood food : member.getFavoriteFoods()) {
                System.out.println(" - " + food.getFoodName());
            }
        }
    }

    // Update the member's name
    public static void updateMemberName(EntityManager em, Long memberId, String newName) {
        Member member = em.find(Member.class, memberId);
        if (member != null) {
            member.setName(newName);
            em.merge(member); // Merge the updated member back into persistence context
        }
    }

    // Delete the member
    public static void deleteMember(EntityManager em, Long memberId) {
        Member member = em.find(Member.class, memberId);
        if (member != null) {
            em.remove(member); // CascadeType.ALL will automatically delete favorite foods
        }
    }
}

 

3. 코드 설명

 

EntityManager: JPA에서 데이터베이스와 상호작용하는 핵심 객체로, 데이터를 조회하거나 저장할 때 사용.

EntityTransaction: 데이터베이스 작업은 트랜잭션 안에서 이루어져야 함. begin(), commit(), rollback() 메서드를 사용해 트랜잭션을 관리.

Persist: em.persist()를 호출하면 엔티티를 영속성 컨텍스트에 저장하고, 트랜잭션이 커밋되면 데이터베이스에 반영.

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

Remove: em.remove()로 엔티티를 삭제.

CascadeType.ALL: Member를 삭제할 때, 연관된 FavoriteFood 엔티티도 함께 삭제되도록 함.

 

4. 어노테이션 활용

 

@Entity: MemberFavoriteFood 클래스가 각각 데이터베이스의 테이블에 대응.

@OneToMany@ManyToOne: MemberFavoriteFood 간의 관계를 매핑하여, 회원이 여러 개의 좋아하는 음식을 가질 수 있도록 함.

@GeneratedValue: ID가 자동으로 생성되도록 설정.

 

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