JPA / Hibernate

JPA(Java Persistence API)はDBアクセスの標準仕様、実装が Hibernate。spring-framework と組み合わせて使う。_moc-web-infra

Entity マッピング

  • @EntityDDDの Entity、@Embeddable が Value Object に対応。
  • @Column(nullable=false) 指定しないと既定で nullable。String は既定で varchar(255)text にしたいなら @LobcolumnDefinition="text"
  • FK: @ManyToOne + @JoinColumn、逆側は @OneToMany(mappedBy=...)CascadeType.ALL で親削除時に子も削除。
  • Kotlin の data class は FetchType.LAZY が機能しない等の理由で Entity には非推奨。

FetchType(N+1問題)

関連カラムの読み込みタイミング。

  • EAGER: Entity取得時に即読み込み(@OneToOne/@ManyToOne の既定)。
  • LAZY: getter アクセス時に読み込み(@OneToMany/@ManyToMany の既定)。
    ドメインモデルに関連モデルをフィールドで持たせると LAZY の意味が薄れ N+1 を招く。

クエリ

  • JPQL: SQL風だがカラム名でなく Entity プロパティ名を使う(select e from Entity e)。日付演算には未対応で、範囲検索などは nativeQuery=true で生SQL(DB依存)。
  • Criteria Builder: 型付きの JPQL クエリビルダ。
  • Repository メソッド命名規約(findByXxxAndYyy)で自動実装。
  • インデックス: @Table(indexes=@Index(columnList="a,b"))

ライフサイクル

NEW → (persist) → MANAGED ⇄ DETACHED(detach/clear ⇄ merge)、MANAGED → (remove) → REMOVED。明示的に保存メソッドを呼ぶのは非OOP的という見方(ドメインモデル貧血症)。

  • save()saveAndFlush(): tx スコープ外で saveAndFlush を呼ばない。

Pagination

Page<T> を返し最後の引数に Pageable。native query では @Query(countQuery=...) を併記。

連番

@GeneratedValue は主キーにしか付けられない。非idの連番(SEQUENCE/@SequenceGenerator)は主キー化が必要で @IdClass などの工夫が要る。

関連