1. Entity
- DB의 테이블과 매칭 되는 개념
ex) DB 구조
CREATE TABLE Student (
s_number BIGINT(20) NOT NULL AUTO_INCREMENT,
name varchar(255) not null,
);
ex) Entity 구조
@Entity
public class Student{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private long sNumber;
@Column(nullable = false)
private String name;
// getter, setter...
}
2. EntityManager
Entity를 관리하는 역할을 수행하는 클래스이다.
엔티티 매니저 내부에 영속성 컨텍스트(Persistence Context)
라는 걸 두어서 엔티티들을 관리한다.
영속성 컨텍스트(Persistence Context)
영속성: 비휘발성
컨텍스트: 하나의 환경, 공간으로 이해
영속성 컨텍스트: 영속성 컨텍스트를 관리하는 모든 EntityManager가 초기화 및 종료되지 않는 한 Entity를 영구히 저장하는 환경
EntityManager와 영속성 컨텍스트의 Entity 관리
public class Join{
public void save(String name){
Student s = new Student();
s.setName(name);
// 엔티티 매니저가 있다고 가정.
EntityManager em;
EntityTransaction tx = em.getTransaction();
try{
// 엔티티 매니저에서 수행하는 모든 로직은 트랜잭션 안에서 수행되야 한다.
tx.begin();
// 이렇게 하면 해당 엔티티 매니저의 영속성 컨텍스트에 위에서 만든 student 객체가 저장된다.
// 이제 student 엔티티는 엔티티 매니저의 관리 대상이 되고, 영속성을 가졌다고 말할 수 있다.
em.persist(s);
// 트랜잭션을 커밋한다.
tx.commit();
}catch(Exception e){
// 오류가 났다면 트랜잭션을 롤백 시켜줘야한다.
tx.rollback();
}finally{
// 더 이상 사용하지 않는 자원이므로 엔티티 매니저를 종료시켜줘야 한다.
em.close();
}
}
}
트랜잭션(Transaction)
- 하나의 작업 단위
ex) 상품 결제
- 상품 재고 조회
- 사용자의 잔고 조회
- 상품 재고 -
- 사용자 잔고에서 해당 금액을 뺌
- 주문 완료
위 5가지 작업중 하나라도 오류가 발생하면 전체가 오류라고 보고 맨 처음 상태로 돌려야한다.
이렇게 오류가 났을 때 처음 상태로 돌아가는(rollback) 작업의 단위를 트랜잭션이라 한다.
트랜잭션이 모두 정상 수행됬을 때는 commit을 수행해서 작업 내용을 실제 DB와 엔티티 매니저에 반영한다.
쓰기 지연 SQL 저장소
- 영속성 컨텍스트 안에는 쓰기 지연 SQL 저장소라는 공간이 따로 존재한다.
public class Join{
public void save(String name){
Student s1 = new Student();
s.setName(name);
Student s2 = new Student();
s.setName(name);
// 엔티티 매니저가 있다고 가정
EntityManager em;
EntityTransaction tx = em.getTransaction();
try{
// 엔티티 매니저에서 수행하는 모든 로직은 트랜잭션 안에서 수행되야 한다.
tx.begin();
//쿼리는 전송되지 않는다.
em.persist(s1);
em.persist(s2);
// 커밋하는 시점에 쿼리가 전송된다.
tx.commit();
}catch(Exception e){
// 오류가 났다면 트랜잭션을 롤백 시켜줘야한다.
tx.rollback();
}finally{
// 더 이상 사용하지 않는 자원이므로 엔티티 매니저를 종료시켜줘야 한다.
em.close();
}
}
}
트랜잭션을 사용하지 않는다고 가정하고코드 동작을 살펴보자.
- 쿼리가 두 번 날아갈 것이다.
- 만약에 s2를 저장하는 시점에서 롤백을 해야할 때는 날리지 않아도 될 s1 에 대한 삽입 쿼리를 날리게 된 격이다.
하지만 쓰기 지연 SQL 저장소 및 트랜잭션에 의해 아래와 같이 동작한다.
- 트랜잭션이 커밋 되기 직전까지 모든 쿼리문은 영속성 컨텍스트 내부의 쓰기 지연 SQL 저장소에 저장된다.
- 트랜잭션이 커밋되는 순간 모든 쿼리가 한 방에 날아간다.
- 만약 트랜잭션 내부에서 오류가 나서 롤백을 해야한다면 애초에 날리지도 않을 쿼리를 날리지도 않는다.
3. EntityManagerFactory
- 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대 공유하면 안된다.
- 동시성(Concurrency):
사용자가 체감하기에는 동시에 수행하는 거처럼 보이지만 사실 사용자가 체감할 수 없는 짧은 시간단위로 작업들을 번갈아가면서 수행되는 것이다.
ex) 각 스레드들이 동시에 동작하는 거 같지만 알고 보면 스레드들이 아주 짧은 시간마다 번갈아가면서 작업을 수행하고 있는 것이다. - 병렬(Parallelism)
우리가 생각하는 진짜 동시에 실행하는 개념을 생각하면 된다.
실제로 동시에 여러 작업이 수행되는 개념
각 스레드들이 동시에 동작한다.
내가 데이터를 수정하고 있는데 다른 스레드에서 해당 데이터를 미리 수정해버리면 안되기 때문에
엔티티 매니저는 하나를 공유하면 안 되고, 상황에 따라 계속 만들어줘야한다.
엔티티 매니저를 만드는 것이 엔티티 매니저 팩토리이다.
public class Join{
public void save(String name){
Student s1 = new Student();
s1.setName(name);
// META-INF/persistence.xml에서 이름이 db인 persistence-unit을 찾아서 엔티티 매니저 팩토리를 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("db");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try{
// 엔티티 매니저에서 수행하는 모든 로직은 트랜잭션 안에서 수행되야 한다.
tx.begin();
// 이렇게 하면 해당 엔티티 매니저의 영속성 컨텍스트 위에서 만든 student 객체가 저장된다.
// 이제 student 엔티티 매니저의 관리 대상이 되고, 영속성을 가졌다고 말할 수 있다.
em.persist(s1);
// 트랜잭션을 커밋한다.
tx.commit();
}catch(Exception e){
// 오류가 났다면 트랜잭션 롤백 수행
tx.rollback();
}fianlly{
// 더 이상 사용하지 않는 자원이므로 엔티티 매니저를 종료시켜줘야 한다.
em.close();
}
}
}
Entity Manager Factory에서 제품(Entity Manager)를 찍어내는 개념
Entity Manager Factory는 Entity Manager와 달리 여러 스레드가 동시에 접근해도 안전하다.
단순히 Entity Manager만 찍기 때문
Entity Manager Factory를 짓는 비용은 크다
따라서 Entity Manager Factory는 DB당 하나 밖에 사용하지 않는다.
'개발 > JPA' 카테고리의 다른 글
[JPA] @OneToMany orphanRemoval (0) | 2023.09.10 |
---|---|
[JPA] @OneToMany 단방향 매핑의 단점 (0) | 2023.09.10 |
JPA 무한 재귀 해결방법 (0) | 2023.09.10 |
JPA 주요속성(@JoinColumn, @MaynToOne, @OneToMany) (0) | 2023.09.10 |
JPA 지연로딩(LAZY) 즉시로딩(EAGER) (0) | 2023.09.10 |