[問題] Spring Data JPA no Session問題
※問題類別: Spring Data JPA
※系統環境: bellsoft-jdk-11.0.14.1
很久沒有使用 JPA,最近可能會用到
又回頭看了 Spring Data JPA
一開始使用 Spring Boot 練習
第一問題通常會遇到 infinite recursion 的 JsonMappingException
所以使用 Jackson 的各種 annotation 或是轉 DTO 來解
因為覺得 Spring Boot 背後做太多事,可能會錯過什麼
所以改用 Spring 來練習一下
果不其然就發生了 LazyInitializationException - no Session
查了一下,Spring Boot 的 spring.jpa.open-in-view 預設為 true
讓 entity 在脫離 transaction scope 時
還能使用 oiv 的 connection 去查 lazy entity 的資料
不過查資料時,是建議關閉這個功能,畢竟拉長佔用 connection 的時間
而查到的幾種解法
1. 把 @Transactional 設定在操作 lazy entity 的 method
因為 Spring Data JPA 執行流程,會導到 SimpleJpaRepository 來處理
而 SimpleJpaRepository 在 class 上宣告了 @Transactional(readOnly = true)
因為練習的 service 內的 method,可能會查詢多次
不希望每個查詢都使用一個 read only transaction
所以在 XxxService 的 class 也使用 @Transactional(readOnly = true)
希望多個查詢使用同一個 read only transaction
所以我在 XxxService 的 class 上也使用 @Transactional(readOnly = true)
然後在執行 insert, update, delete 的 method 使用 @Transactional
https://imgur.com/2nVTBXH
![](https://i.imgur.com/2nVTBXH.jpg)
但如果要使用 @Transactional 來解 no Session 的錯誤
那就變成要把 @Transactional 設定在 controller 的 method 了
這和 open-in-view 的做法似乎差別不大,只是用同一個 connection 而已?
2. 把 entity 關聯設為 FetchType.EAGER
即使沒用到,也強制查詢關聯的 table,應該也不會這樣使用
3. Spring Boot 設定 hibernate.enable_lazy_load_no_trans=true
(Spring 的話,在設定 EntityManagerFactory 時,設定 jpa properties)
似乎也是 Hibernate 實做,另開個 Session 查詢 lazy entity
-------------------------------------------------------------------
查到以上的做法都是不建議的
4. 避免使用雙向關聯
但是單向關聯就會發生了
總不會 entity 都不要關聯,每個 entity 自行操作?
5. 使用 JOIN FETCH
使用 @Query 自己下 JPQL
6. 使用 DTO
Spring Data JPA 的 projection 功能
雖然 interface based projection 有支援 nested projection
但是使用 @Query 時,JPQL 卻不知怎麼下
例如有一個 Employee 的 entity,和關聯的 Department
https://imgur.com/rebQiC7
![](https://i.imgur.com/rebQiC7.jpg)
projection 的 interface 這樣宣告
https://imgur.com/pcB86Q6
![](https://i.imgur.com/pcB86Q6.jpg)
JPQL 或 native SQL 都無法設值到 department 的 deptName
https://imgur.com/XRhI92i
![](https://i.imgur.com/XRhI92i.jpg)
除非把關聯的 entity 內的 field 全部移到 Employee 內,只有一層的結構
而 class based projection 是另外定義 DTO class
但是不支援 nested projection
也就是如果我希望 DTO 能長這樣,似乎是不可行的
https://imgur.com/EzAIeV6
![](https://i.imgur.com/EzAIeV6.jpg)
而且 DTO 的 constructor 似乎要符合查詢的 field 數目
我使用 overload 的 constructor 想用在多種查詢
也遇過 no suitable constructor 之類的錯誤
以及 ConverterNotFoundException: No converter found ... 的錯誤
難不成不同的查詢,就需要一個對應的 DTO 嗎?!
6.1. 使用 library 把 entity 轉成 DTO
也有看到使用 modelmapper 做 converter 的範例
不過這個範例我不知道為什麼可以成功
https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
因為他的 service 和 controller 都沒看到使用 @Transactional
也就是使用 SimpleJpaRepository 的 read only transaction
那在 controller 使用 ModelMapper 時,就會炸 no Session 了
我是把 ModelMapper 移到 service 內執行
因為 @Transactional 也都是掛在 service layer
6.2. 是否直接把 entity 做 deep copy 到結構完全一樣的 DTO 就好了
還沒測試,只是突然想到
以前在用 JPA 時,只是使用而沒深入了解
沒有發生 no Session 的錯誤
同樣雙向關聯的 entity,同樣是把 transaction 掛在 service layer
現在回想,當時在 render JSP 時,為什麼沒問題呢?
後面還有 N + 1 的問題
目前查到是使用 FETCH JOIN,或是 JPA 2.1 的 @EntityGraph
Spring JDBC 用久了,現在覺得 Data JPA 用起來還挺不順手
如果要直接操作 entity,就要處理 no Session 的問題
很多教學的範例,其 entity 都只是簡單的 field,甚至沒有關聯的 entity
但實務上應該不會這樣吧?
如果要操作 DTO,表示要大量使用 JPQL 或 Data JPA 的 query methods?
題外話
不知道 JOOQ 好不好用,Spring Boot 有看到
但似乎都是 Data JPA 和 MyBatis 較多
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.249.65.177 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/java/M.1651812876.A.961.html
→
05/06 14:30,
2年前
, 1F
05/06 14:30, 1F
→
05/06 14:31,
2年前
, 2F
05/06 14:31, 2F
→
05/06 14:32,
2年前
, 3F
05/06 14:32, 3F
→
05/06 14:35,
2年前
, 4F
05/06 14:35, 4F
→
05/06 14:36,
2年前
, 5F
05/06 14:36, 5F
→
05/06 14:38,
2年前
, 6F
05/06 14:38, 6F
→
05/06 14:40,
2年前
, 7F
05/06 14:40, 7F
→
05/06 14:48,
2年前
, 8F
05/06 14:48, 8F
感謝 s大說明
其實是自己在練習,把查到的方式都試一遍
然後想問實務上,使用哪種方式居多而已
當然實務也還是得看情況選擇使用,沒有標準答案
只是以前都只是 MVC + JSP 在使用
加上短暫使用 JPA,後來就長期使用 JDBC template
使用 JDBC template 其實就是一次查詢
把 view 要用到的資料一次查回到 VO
重點在 SQL 的調教而已
現在會需要使用 Data JPA,使用 RESTful 回傳 JSON
但是 JSON 的內容依 API 需要有各種內容
例如可能只有 Employee,也可能會需要有 Department
流量不大的情況,的確可以使用 open-in-view
直接把 entity output JSON 就好
然後去處理 N + 1 的 SQL 問題
只是想問看看,哪個方式處理會比較好
例如流量若較大,能盡早結束 transaction 關閉 connection
是否就是使用 Data JPA 的 projection 直接轉 DTO
那就是要去解決,怎麼樣能像 entity 那樣結構的 DTO 而已
若要符合自己提問的情況,依照過去使用 JDBC template 的情況
會使用 DTO 來處理,只是 兩種 projection 我都試不出符合 DTO 的結構
→
05/06 15:09,
2年前
, 9F
05/06 15:09, 9F
※ 編輯: jtorngl (111.249.65.177 臺灣), 05/06/2022 15:31:03
推
05/06 18:45,
2年前
, 10F
05/06 18:45, 10F
→
05/06 19:03,
2年前
, 11F
05/06 19:03, 11F
→
05/06 19:05,
2年前
, 12F
05/06 19:05, 12F
→
05/06 19:07,
2年前
, 13F
05/06 19:07, 13F
→
05/06 19:08,
2年前
, 14F
05/06 19:08, 14F
→
05/06 19:10,
2年前
, 15F
05/06 19:10, 15F
推
05/15 02:47,
2年前
, 16F
05/15 02:47, 16F
→
05/15 02:48,
2年前
, 17F
05/15 02:48, 17F
java 近期熱門文章
PTT數位生活區 即時熱門文章