스프링/JPA

[JPA 기초] 기본 Entity 설정시 사용되는 annotation 정리

nomoreFt 2022. 4. 5. 15:50

@PersistenceContext

이 어노테이션이 있으면 EntityManager가 주입된다.
build.gradle의 jpa보고 yml 파일 읽어서 설정된 대로 만들어서 DI 해줌.
EntityManger 객체는 JPA에서 CRUD를 호출하는 기능

   @Repository
public class MemberRepository {

    /*이 어노테이션이 있으면 EntityManager가 주입된다.
      jpa보고 yml 파일 읽어서
     */
    @PersistenceContext
    private EntityManager em;

@Embeddable (내장타입 대상 클래스의 상단) @Embedded (내장타입을 사용하는 객체의 변수 설정 위)

Jpa의 내장타입이란 뜻입니다. Jpa에서 domain 생성시 경우에 따라 안에 들어가는 POJO객체

@Embeddable//jpa의 내장타입이란 뜻
@Getter @Setter
public class Address {

    private String city;
    private String street;
    private String zipcode;

}




@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded//둘 중 하나만 있어도 됨
    private Address address;

    private List<Order> orders = new ArrayList<>();//
}

@Inheritance(strategy = InheritanceType.SINGLE_TABLE) (strategy = InheritanceType.JOINED) (strategy = InheritanceType.TABLE_PER_CLASS)

  • abstract class를 상속받을 구현체들마다 어떻게 대응할 지, 전략을 정하는 기능이다.
  • strategy join이 제일 정교, single 다 때려박기, table_per_class 상속받는 테이블마다 전부 생성
/*
* 
*/
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)/
@Getter @Setter
public abstract class Item {//상속관계 전략을 심어줘야한다. (여긴 Single Table)

    @Id @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;
}

@OneToMany(mappedBy = "FK가 있는 다수에서 선언된 field명")

   @OneToMany(mappedBy = "car")

( Car car(1) ---- ArrayList list - 타이어() , Member(1) - Order() 1 대 다에서 종속을 의미")

@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = "member")//order Table에 있는 member 필드에 매핑된거야.
    //내가 매핑을 하는애가 아니고 나는 매핑된 거울일 뿐이야. (읽기 전용)
    private List<Order> orders = new ArrayList<>();
}

@DiscriminatorColumn(name = "dtype") -> @DiscriminatorValue("M")

  구현체와 상속받아 사용되는 Entity간의 구별

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)//strategy =  제일 정교 single 다 때려박기
@DiscriminatorColumn(name = "dtype")
@Getter @Setter
public abstract class Item {//상속관계 전략을 심어줘야한다. (여긴 Single Table)

    @Id @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;
}




@Entity
@Getter @Setter
@DiscriminatorValue("M")
public class Movie extends Item {

    private String director;
    private String actor;
}

@Enumerated(EnumType.STRING) (EnumType.ORDINAL)

  • Enum Type.STRING에서 String 상태값으로 바로 들어가는 것. & EnumType.ORDINAL숫자로 연계되서 상태값으로 들어가는것 (1,2 이렇게)
  • String은 가급적 사용 X(중간에 상태 하나 추가되면망함)
  • @Entity @Getter @Setter public class Delevery { @Enumerated(EnumType.STRING) private DeliveryStatus status; //READY, COMP }

#### @OneToOne

     1대1 매핑이라 더 자주 쓰이는 Table에 FK를 놓는다. (어디다 놔도 가능한데 가급적)
     연관관계 주인을 FK에 가까이에 있는 자주쓰이는 Table을 주인으로 둔다.

```java

@Entity
@Table(name = "orders")
@Getter
@Setter
public class Order {

    @OneToOne
    @JoinColumn(name = "delivery_id")
    private Delevery delevery;
}//FK를 가지고 있는 주인. JoinColumn으로 delivery_id 연결해놓는다.

@Entity
@Getter @Setter
public class Delevery {

    @OneToOne(mappedBy = "delevery")
    private Order order;

}//종속관계가 되어버린 Delivery는 mappedBy로 Order의 수정에 의해서만 수정되는 거울로 만들어놓는다.

@Transactional()

JPA의 Data 변경 모든 동작들은 @Transactional()안에서 이루어져야 LAZY 로딩 등의 동작들이 작동한다.
주로 Spring 로직이 많이 사용되었으니 javax의 Transactional보단 spring의 Transactional이 더 사용할 수 있는 도구 개수가 많다.

   @Transactional
public class MemberService {

읽기(select)에는 가급적이면 @Transaction(readOnly = true)를 넣어주면 좋다.
영속성 컨텍스트를 flush안하고 dirtyCheck을 안하고 db에 따라서는 읽기 전용 Transaction에 대한 이점이 있어서 리소스가 덜 사용 되기도 한다.
메서드에 설정해줌

    @Transactional(readOnly = true)
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }

@XtoOne fetchType EAGER to LAZY

필수! X to One 어노테이션들은 fetchType이 EAGER (자신 객체 불러올때 (XtoOne)으로 연관지어진 객체들 즉시 모두 가져오는것) 으로 설정되어있다.
이론상 가져오는 상대방은 1개의 객체라 즉시 불러오는게 합리적인것 처럼 보이나, 실상 JPQL로 불러올 때, select문으로 가져오기 때문에, 100개의 Many 진영의 객체를 가져온다면
각 1개를 가져올때마다 단문의 쿼리를 100번씩 수행할 수도 있다. (one쪽의 전체 select) 필수적으로 X to One으로 매칭된 애들은 fetchType을 LAZY로 수정해줘야한다.

EX)


     @OneToOne(mappedBy = "delevery", fetch = FetchType.LAZY)
    private Order order; 

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "item_id")
    private Item item;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id") //One의 참조키의 원래 column명
    private Order order;  

X to Many에서 원래는 persist(orderItemA),persist(orderItemB),persist(orderItemC), persist(order)
orderItems 위에 cascade = CascadeType.ALL 타입을 붙이면 persist(order)만 해도 orderItem들이 종속적으로 persist가 된다.

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<>();