Django의 orm을 배울 때
뭔가 새로웠지만 신기하고 재밌음에도
편리하다는 느낌까지 받았다.
JPA는 과연...
너도 django만큼 날 만족 시킬 수 있니?
jpa는
Java Persistence API의 약자로
Java에서 사용하는 대표적인 orm이다.
JDBC를 공부 할 때
JPA도 JDBC를 활용하여 만든거라 했는데,
사실 사이에 Hibernate ORM 하나가 더 껴있다.
Hibernate은 JPA 인터페이스의 구현체이고,
Hibernate 외에도
EclipseLink, DataNucleus등이 있다.
Persistence는
영속성 혹은 지속성을 뜻한다.
무언가의 상태를 지속하는 것 같다.
여기서 이 무언가는 entity를 뜻하며,
DB에 저장되는 객체인
Spring에서 말하는 entity와 같은 것이다.
그래서 Entity Manager는
1차 캐시에 들어오는 entity의 수명주기를 관리하고,
쓰기 지연 저장소를 통해 commit
할 때 까지
쿼리를 실행 시키지 않으며,
commit
이나 flush
이후 DB에 쿼리를 실행시킨다.
flush
는 1차 캐시안의 entity의 변경 내용을
DB에 반영하는 것으로
transaction
을 통해 commit
하는 것과 달리
Entity Manager
를 통해 진행 되기 때문에,
flush
이후에도 1차 캐시를 비우지 않는다.
그러니까 entity의 변경사항만 db에 전송하는 것
Spring Data JPA가 아닌
일반 JPA는
EntityManager를 통해 entity를 관리하고,
em.getTransaction()
을 통해
생성한 객체로transaction을 관리한다.
em.persist()
를 통해 1차 캐시에 entity객체가 저장되고
쓰기 지연 SQL 저장소에 쿼리가 등록된다.
tx.commit()
을 통해 쓰기 지연 SQL 저장소에 등록된 쿼리가 실행되고 실행된 쿼리는 저장소에서 삭제한다.
em.
에는 find
나 flush
등 여러 메서드가 존재
@Entity
@Table(name="USER")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
}
Entity에 해당하는 클래스에
@Entity
을 통해 해당 클래스가 Entity라는 것을 알린다.
@Table
에서 name을 통해 DB에 있는 Table의 이름을 설정할 수 있다.
@Id
를 단 필드는 primary key가 되며
@GeneratedValue
를 통해
primary key 생성 전략을 선택할 수 있다.
IDENTITY
SEQUENCE
DB Sequence를 활용하는 방식으로
DB에서 Sequnece를 생성하고,
Entity 클래스에 @SequenceGenerator
와
@GeneratedValue
에 generator를 넣어 사용한다.
@Entity
@SequenceGenerator(
name = "USER_SEQ_GENERATOR",
sequenceName = "USER_SEQ",
initialValue = 1,
allocationSize = 1
)
public class Member {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "USER_SEQ_GENERATOR"
)
private Long id;
}
TABLE
성능이슈로 별로 사용안함
AUTO
DB의 종류에 따라 알맞는 전략을 자동으로 선택해줌
@Column(nullable = false)
private String name;
Entity 클래스에서 일반적으로 쓰이는 필드를
DB의 column에 매핑하는 annotation으로
nullable
, updatable
, unique
등의 매개변수가 있다.
사실 @Coulumn
annotation 없어도 알아서 등록하는거 같다.
하지만, 명시적으로 지정하기 위해 사용하는것 같다.
만약 사용 시 nullable
의
default값은 true이기 때문에 유의 해야한다.
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
@ManyToOne
@JoinColumn(name="MEMBER_ID")
private Member member;
...
}
@ManyToOne
, @OneToOne
등을
@JoinColumn
과 같이 활용해
Entity간의 연관관계 매핑이 가능하다.
@JoinColumn
에서 name
에 들어가는 값은
참조 Entity의 primary key값의 이름이다.
@Entity
@Table(name="USER")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
@OneToMany(mappedBy = "member")
private List<POST> posts = new ArrayList<>();
...
}
@OneToMany
를 활용해 1:N의 관계에서
1에 해당하는 Entity에서
N에 해당하는 Entity List를 불러올 수 있다.
물론 DB에 저장되는 값은 아니고,
1에 해당하는 Entity를 find 할 때
join query를 통해 알아서 가져오는거 같다.
mappedBy
에 들어가는 값은
N에 해당하는 Entity 클래스에서
관계를 매핑할 때 사용한 필드의 이름이다.
역시 python인가..
jpa도 재미는 있지만,
복잡하고 django orm보다 어려운거 같다.