[Spring] Persistence Context?


0. Overview


JPA管理の持続性
永続性.
:永続性コンテキスト(Persistence Context)は、通常、エンティティを永続的に格納する環境を指します.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa");

// EntityManagerFactory를 통해 EntityManager 객체 생성
EntityManager em = emf.createEntityManager();
→em(EntityManager)を使用してCRUDを処理します.
このように処理されたEntityは、データベースに直接反映されるのではなく、永続性コンテキストで保持および管理されます.
Book book = new Book();
// 필드 맵핑 setXxx() 생략..

em.persist(book); // 영속성 컨텍스트에 book Entity 저장 (DB가 아님)
アトリビュートマネージャの作成時に永続性コンテキストが作成されるため、永続性コンテキストにアクセスして管理できます.em.persist(book);現在、永続性コンテキストにbookというエンティティが含まれています.
では、DBに本当に反映されるのはいつですか?

🧃 エンティティのライフサイクル


  • 非永続性(new/transient):永続性コンテキストにまったく関係のない状態
    :Book book = new Book()

  • 永続性(managed):永続性コンテキストに格納されたステータス
    : em.persist(book)

  • 準永続性(分離):永続性コンテキストに格納され、分離された状態

  • 削除(Removed):削除されたステータス
    : em.remove()
  • persist()は、マネージャという名前の永続的な状態に入ります.flush()は、永続的な状態にあるentityDB에 보낼 때を使用します.
    1)非永続状態(new/transient):純粋なエンティティオブジェクトのみが作成された状態
    Entity Managerで永続コンテキストに保存されていません
    Book book = new Book();
    book.setBookName("어른왕자");
    2)持続状態(Managed):Entity Managerで持続性コンテキストにEntityを保存する
    →永続性コンテキストによって管理される「エンティティ」(Managed)
    em.persist()
    3)準永続状態(分離):永続性コンテキストが以前管理していたエンティティを管理しなくなった場合、準永続状態になります.
    // Book entity를 영속성 컨텍스트에서 분리, 영속 -> 준영속 상태
    em.detach(book);
    
    // 혹은
    em.close() // 영속성 컨텍스트 닫기
    
    // 혹은
    em.clear() // 영속성 컨텍스트 초기화
    4)削除ステータス(削除):永続コンテキストとデータベースからEntityを削除
    em.remove(book);

    🎂 永続性コンテキストのフィーチャー


    1)持続性コンテキストEntity를 식별자(PK, 기본키, @Id로 Table의 기본 키와 맵핑한 값)に区分される.
    ->永続状態には識別子が必要です.
    2)永続性コンテキストに格納されたEntityTransaction이 Commit되는 순간 실제 DB에 반영,称flush

    🍍 Entity CRUD


    1)エンティティの読み込み


    永続性コンテキストには、1차 캐시と呼ばれるキャッシュがあります.
    永久状態のEntityはすべてここ→Mapオブジェクト状態に格納されます.
    Key : @Id
    Value : Entity Instance
    // 비영속
    Book book = new Book();
    book.setBookName("어른 왕자");
    
    // 영속
    em.persist(book);

    →@Idはプライマリキー識別子値であるため、永続性コンテキストにデータが格納される.조회の条件は기본키(Id)からなる.
    エンティティクエリー
    Book book = em.find(Book.class, 1L);
    →em.find()が呼び出されると、プライマリ・キャッシュでEntityが検索されます.検索するEntityがプライマリ・キャッシュにない場合は、DBでクエリーされます
    つまり、永続性コンテキストを確認してEntityをクエリーし、ない場合はDBでクエリーします.
    これにより、パフォーマンスが向上し、クエリー時間が短縮されます.

    メインキャッシュに検索するEntityがある場合?



    ID 1 LのEntityはメインキャッシュに存在するため、DBにはアクセスしない.

    プライマリ・キャッシュに検索するEntityがない場合(データベースでクエリー)


    Entity ManagerはデータベースをクエリーしてEntityを作成し、プライマリ・キャッシュに保存して永続的なEntityを返します.

    永続エンティティの一貫性の確保


    識別子(Id)クエリによる同一のEntityインスタンスの比較
    Book book = em.find(Book.class, 1L);
    Book book2 = em.find(Book.class, 1L);
    
    System.out.println(a == b); // ?
    →結果はtrue,
    find()を繰り返し呼び出しても、永続性コンテキストは同じEntityインスタンスを返します.(エンティティが一致していることを確認)JDBC의 경우에는 서로 다른 인스턴스로 생성成功しました.

    2)エンティティ登録


    トランザクションをコミットする前に、EntityMangerはEntityをデータベースに格納するのではなく、INSERT SQLを内部クエリー・リポジトリに格納します.
    トランザクションのコミット時に収集されたクエリーをDBに送信
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    
    // EntityManager는 데이터 변경 시 트랜잭션을 시작해야 함
    tx.begin();
    
    em.persist(book1);
    em.persist(book2);
    // 영속성 컨텍스트에만 집어넣은 상태, DB에 들어가지 않은 상태
    // 아직 Insert SQL을 수행하지 않음
    
    // Commit되는 순간 DB에 Insert SQL을 보냄
    tx.commit();
    em.persist()によって、永続性コンテキストにおいて1차 캐시에 Entity를 저장,INSERT SQL 코드를 생성が使用される.
    実際,データベースに反映された瞬間は,tx.commit()が実行されたときである.
    DBへのアクセスには時間がかかります.ディスクは変換可能なので、SQL文を永続的なコンテキストに集約し、一度に()をコミットするとパフォーマンスが向上します.

    トランザクションのコミット後、Entity Managerは永続性コンテキストをリフレッシュします()
    →flush()永続性コンテキストへの変更をDBに同期する
    つまり、登録、変更、削除されたEntityをデータベースに反映します.
    →遅延書き込みSQLリポジトリに集約されたクエリーをDBに送信します.
    これらの永続性コンテキストの変更履歴をDBに同期した後、実際のDBのトランザクション()をコミットします.
    →SQL文を一度にDBに転送するので、パフォーマンスを最適化できる

    3)エンティティの更新(エンティティの変更)


    未使用JPA


    データベース内のデータのSQL文の変更
    UPDATE BOOK
    SET
    	BOOK_NAME=?,
    	AUTHOR=?
    WHERE
    	id=?
    本の発行日フィールドの追加と変更を要求する
    →リリース日を変更するためのSQL文の個別作成
    UPDATE BOOK
    SET
    	PUB_DATE
    WHERE
    	id=?
    →SQL文をビジネスロジックごとにチェックする手間と複雑さが増す(ビジネスロジックはSQLに依存)

    JPAのエンティティ修正方法:変更の検出(dirty checking)


    →em.update()などの方法がなく、自動的にEntity変更をデータベースに反映する機能を変更検出と呼ぶ.
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    
    tx.begin();
    
    // 영속 상태의 Entity 조회
    Book book = em.find(Book.class, 1L);
    
    // 영속 상태의 Entity 데이터 수정
    book.setBookName("어른 왕자");
    
    tx.commit();

    JPAはEntityを永続性コンテキストに保存します.
    初期状態のコピーと保存(スナップショット)
    更新()ポイントでスナップショットとEntityを比較し、変更されたEntityを検索します.

    4)エンティティの削除


    Entityを削除するには、まず削除先のEntityを問い合わせる必要があります.
    // 삭제할 Entity 조회
    Book book = em.find(Book.class, 1L);
    
    em.remove(book); // 엔티티 삭제
    →DELETE SQLも、遅延書き込みされたSQLリポジトリに登録され、トランザクションがflush()をコミットして呼び出すと、実際のDBにQueryが渡されます.