두주·2023년 12월 25일
0

TIL

목록 보기
22/58
post-thumbnail

JPA는 객체와 Database를 매핑한다 (연결한다)

JPA가 객체 지향적으로 데이터베이스를 다루는데,
그 때 테이블과 맵핑되는 객체가 바로 Entity다.

@Entity라는 어노테이션을 지정함으로써
JPA에서 관리하는 객체로 작동한다.

@Entity
@Table(name = "post")
Class Post(
@Column(name = "title")
var title: String

이는 Post라는 클래스의 title이라는 variation이 Post테이블의 title에 매핑된다는 뜻이다.

@Id
@GenetratedValue(strategy - GenerationType.IDENTITY)
Var id: Long? = null

Id를 자동생성하겠다는 뜻.
IDENTITY로 설정하면 DB에 맡긴다는 뜻이다.

위는 Entity의 Primary Key를 지정한 것

@OneToMany
@ManyToOne
@OneToOne
@ManyToMany

등 다양한 어노테이션을 사용하여 객체간 관계를 설정한다.

Persistence Context (영속성 컨텍스트)

우리가 어플리케이션 내에 변수로 데이터를 저장하고 관리하면 데이터는 메모리에서 관리되기 때문에 애플리케이션이 종료되면 데이터가 삭제된다.

이를 영속성이 없다고 말하는데, 반대로 해당 데이터를 DB에 저장함으로써 영속성을 부여할 수 있다.

결국 영속성 = 저장으로 이해하면 될 것 같다.

JPA는 Entity가 영속성 컨텍스트에 포함되어 있는지, 아닌지에 따라 데이터베이스에 변경사항을 저장하여 영속성을 부여할지, 말지를 결정한다.

JPA는 이 영속성 컨텍스트라는 개념을 활용해 아래의 역할들을 수행한다.

1) Entity의 상태 추적
- 영속성 컨텍스트는 Entity가 Transient(New), Managed, Detached, Removed 등의 상태에 있는지 추적한다
- Transient: 아직 영속성 컨텍스트에 포함되지 않은 새로운 Entity 상태
- Managed: 영속성 컨텍스트에 저장된 상태
- Detached: 영속성 컨텍스트에 저장되었다가 분리된 상태
- Removed: 삭제된 상태
- JPA는 이런 Entity의 상태를 통해 트랜잭션 종료 시 DB에 최종적으로 어떠한 쿼리를 보낼지 결정한다.
최종적으로는 트랜잭션이 끝나는 시점에 Managed, Removed 상태의 Entitiy들의 변경사항이 데이터베이스에 반영된다

2) 캐싱(Caching)
- 영속성 컨텍스트 내 Entity를 Map 형태로 임시 저장하여 동일한 Entity를 조회할 시, DB를 직접 조회하지 않고 해당 Entity를 이용할 수 있게 한다.
// 메모리에 캐싱하는 것을 의미하는 것 같다.

3) 지연 로딩(Lazy Loading) 및 즉시 로딩(Eager Loading)
- 연관관계에 있는 Entity를 지연로딩하거나 즉시 로딩할 수 있다.

지연 로딩은 Entity가 실제로 필요한 시점에 DB에서 로드하고
즉시 로딩은 관련있는 Entity를 바로 로딩한다고 볼 수 있다.
관련있는 = foreign key 등

Post를 foreign key로 사용하는 Comment가 있을 때,
Post를 불러올 때 Comment도 다 같이 불러와서 화면에 띄우기 전에 다 준비해 둘 것인가?(즉시 로딩) 혹은 화면에서 Post를 실행했을 때 Comment를 불러올 것인가?(지연 로딩) 의 차이로 볼 수 있다.

4) 트랜잭션(Transaction)을 통한 쓰기 지연
- 우리는 이미 @Trnasactional 어노테이션을 배우며 이 기능을 사용했다.
지연로딩과 유사하게 코드 상에서 Entity를 수정하거나 변경한다고 바로 반영되지 않고 특수한 시점에 Entity의 상태 변경을 통해 SQL 저장소에 쿼리를 저장한다.

최종적으로 트랜잭션이 종료되는 시점, 즉 트랜잭션을 최종 Commit()할 때
모아둔 쿼리를 DB에 보내 DB와 컨텍스트를 동기화한다.
최종적으로 Commit()이 종료되면 DB에 반영이 된다.
이렇게 Commit()종료 이전에 쿼리를 보내 동기화 하는 것을 flush()라고 표현한다.
flush()로 전송된 쿼리는 Rollback이 가능하지만, commit()이 완료되면 트랜잭션이 끝나므로 Rollback 할 수 없다.

5) Dirty Checking
- flush()는 어떻게 쿼리로 보내야하는지를 판단할 수 있을까?

Entity의 변경하는 판단 과정을 Dirty Checking이라고 한다.
- 예를 들어, post의 title을 변경했을 시 Dirty Checking을 통해
"post의 title이 변경되었으니, update 쿼리를 실행해야겠다"라고 판단하는 것이다.

val post = em.find(Post::class.java, postId)
println(post.title) // "Title1"
post.title = "New Title2"

- 주의점으로, Dirty Checking은 Entity가 영속성 컨텍스트에 저장된 상태, 

즉, Managed상태에 대해서만 수정된다.

JPA의 Entity Manager
위에서 언급된 영속성 컨텍스트를 두어, Entity를 관리하는 주체가 Entity Manager이다.
@PersistenceContext 어노테이션을 통해 주입할 수도 있고, 생성자 주입을 했을 시에도 자동적으로 주입된다.

@Service
Class MyService {

@PersistenceContext
Private lateinit var entityManager : EntityManager

}

EntityManager는 여러 종류의 함수를 지원하여 Entity의 상태를 변경한다.

JPA Repository

interface PostRepostiroy : JpaRepository<Post, Long> {

	fun findByTitle(title: String) : List<Post> 
	
}

interface PostRepository : JpaRepository
// JpaRepository를 상속받고,
<Post, Long> 
//Entity는 Post고 Post의 Primary Key = Long의 자료형이란 것을 알려줌!

이렇게 인터페이스를 정의하면, Spring Data JPA가 인터페이스의 구현체를 자동으로 생성한다.

profile
야옹.

0개의 댓글