JPA / Hibernate
JPA(Java Persistence API)はDBアクセスの標準仕様、実装が Hibernate。spring-framework と組み合わせて使う。_moc-web-infra
Entity マッピング
@EntityがDDDの Entity、@Embeddableが Value Object に対応。@Column(nullable=false)指定しないと既定で nullable。Stringは既定でvarchar(255)、textにしたいなら@LobかcolumnDefinition="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 などの工夫が要る。