JPA
- DBアクセスの標準仕様
FetchType
関連カラムの読み込みのタイミングを決める
FetchType.EAGER: entity取得時に読み込み.@OneToOne,@ManyToOneではデフォルト
FecthType.LAZY: 関連フィールドにアクセスした時に(getter内で)読み込み.@ManyToMany,@OneToManyではデフォルト
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
var tweets: List<Tweets>? = null,-
2022-10-03 q : DDD のドメインモデルにマップする時関連モデルもフィールドに含めるべきなのか?
- それだと
LAZYにしている意味が無くなる
- それだと
JPA Foreign Key
- 外部キー の参照先を持ちたい時
@Entity
@Table(name = "users")
data class ParentEntity(
@Id
@Column(name = "id")
var id: UUID? = null,
@OneToMany(mappedBy = "user_id", cascade = [CascadeType.ALL])
var children: List<Child>? = null
)create table products (
id uuid primary key not null,
user_id uuid not null
);
alter table products add constraint fk_product_user_id
foreign key (user_id)
references users (id);は以下に対応
@Entity
@Table(name = "products")
data class ProductEntity(
@Id
@Column(name = "id")
var id: UUID? = null,
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "user_id")
var user: UserEntity? = null
)カスケーディング
CascadeType.ALL: を@OneToMany等につけると, エンティティ削除時にその参照先も削除される
Entity
-
SpringBootでEntity設計時に知りたいアノテーション - Qiita
@Column(nullable = false)しないとdefaultは nullableぽい
-
@Entityが DDD Entity -
@Embeddableが Value Object -
data classを使うべきでないらしい
FecthType.LAZYが機能しないらしい?
lifecycle
○ ◎
new | ^ GC
v |
+---------+
| NEW | <--------------+
+---------+ |
find/JPQL | |
○----------------------+ | |
| | persist |
v v |
+---------+ merge +---------+ remove +---------+
| | -------> | | --------> | |
|DETACHED | <------- | MANAGED | | REMOVED |
| | clear | | <-+ | |
+---------+ detach +---------+ | +---------+
^ | |
| +------+
| refresh
| setter
v
+-------------+
+-------------+
| Database |
+-------------+
- ドメインモデル貧血症
- どうやら明示的に保存するメソッドを呼ぶのはアンチパターンらしい
- 非OOP的
mapping
String型はvarchar(255)にマッピングされるのか,@Column.lengthのデフォルト値は255.textにしたい時は@LobかcolumnDefinition = "text"使う- Column (Java EE 5 SDK)
- (お気持ち): レビュー時知ってたら弾いてくれ
@Transactional
@Transactionalについて何も知らない- Spring Boot + Spring Data JPA で宣言的トランザクションによるDB制御をするサンプルコード - Qiita
- 【Java・SpringBoot】明示的トランザクション処理(SpringBootアプリケーション実践編21) - Qiita
- 4.2. ドメイン層の実装 — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.0.2.RELEASE documentation
TransactionRequiredException
- Spring Data JPAのEntityの相互参照とその注意点 - Qiita
デバッグ
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql=traceを application.yaml に書くとSQLとバインドされたパラメータがわかる
SpringでSQLのパラメータログに出す
application.yamlを
logging:
path: "logs/"
level:
org:
hibernate:
SQL: DEBUG
type:
descriptor:
sql: TRACE
- 期間とかパラメータ取れるようになったのでそれを考慮したテストを書く
Pagination
2022-07-21
ところで, JPA Paginationについても詳しくないな
-
Page,PageRequestPageRequestに対応するためには- 最後の引数に
pageable: Pageable - 返り値型を
Page<Entity> @Query(countQuery = "SELECT count(*) FROM ...")を用意する
- 最後の引数に
-
nativeQuery使っている時にPage<T>返したいときどうするのか
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value="SELECT * FROM USERS WHERE LASTNAME = ?1", nativeQuery=true)
Page<User> findByLastname(String lastname, Pageable pageable);
}save(), saveFlush()
- tx スコープ内にいないのに
Repository.saveAndFlush()を呼んでいた ->save()にした save(),saveAndFlush()
参考文献
- JPA と DDD の関係で僕が思っていること - Qiita
- SpringBootのDataJPAに戦術的DDDの要素を導入するにはどうすれば良いか調べてみた - クソ雑魚エンジニアのメモ帳
- データベースとの同期
- 少し複雑な関連のデモ(JPA 2.1のおさらいメモの補足) - Qiita
- MultipleBagFetchException - Thoughts on Software design and development
- Spring Data JPA において MultipleBagFetchException と LazyInitializationException のいずれかの例外が投げられる - Qiita
- https://disconnect.no-ip.org/wordpress/2020/02/13/spring-bootでlazyinitializationexceptionが発生する場合
- 2022-10-03 「N+1問題」が起きないコーディングをしよう。|Spring Data JPAでAPIを実装する