![](/img/trans.png)
[英]How to implement Transactional for multiple updates in single method Springboot JPA
[英]How to make multiple call of @Transactional method to a single transaction
我有一個方法
@Transactional
public void updateSharedStateByCommunity(List[]idList)
從以下REST API調用此方法:
@RequestMapping(method = RequestMethod.POST)
public ret_type updateUser(param) {
// call updateSharedStateByCommunity
}
現在 ID 列表非常大,比如 200000,當我嘗試處理它時,它需要很多時間並且在客戶端發生超時錯誤。
因此,我想將其拆分為兩個調用,每個調用的列表大小為 100000。
但是,問題是,它被認為是 2 個獨立的交易。
注意:2 次調用是一個例子,如果數字 id 更大,它可以分為多次。
我需要確保對單個事務的兩個單獨調用。 如果 2 個調用中的任何一個失敗,則它應該回滾到所有操作。
另外,在客戶端,我們需要顯示進度對話框,所以我不能只使用超時。
對您的問題 IMO 最明顯的直接答案是稍微更改代碼:
@RequestMapping(method = RequestMethod.POST)
public ret_type updateUser(param) {
updateSharedStateByCommunityBlocks(resolveIds);
}
...
And in Service introduce a new method (if you can't change the code of the service provide an intermediate class that you'll call from controller with the following functionality):
@Transactional
public updateSharedStatedByCommunityBlocks(resolveIds) {
List<String> [] blocks = split(resolveIds, 100000); // 100000 - bulk size
for(List<String> block :blocks) {
updateSharedStateByCommunity(block);
}
}
如果此方法在同一個服務中,則原始updateSharedStateByCommunity
中的@Transactional
不會做任何事情,因此它會起作用。 如果您將此代碼放入其他一些 class 中,那么它將起作用,因為 spring 事務的默認傳播級別是“必需的”
所以它滿足了苛刻的要求:你想要一個單一的交易——你已經得到了。 現在所有代碼都在同一個事務中運行。 現在每個方法都以 100000 運行,而不是所有的 id,一切都是同步的:)
然而,由於許多不同的原因,這種設計是有問題的。
正如您在問題的最后一句中所說的那樣,它不允許跟蹤進度(向用戶顯示)。 REST 是同步的。
它假設網絡是可靠的並且等待 30 分鍾在技術上不是問題(更不用說必須等待的 UX 和“緊張”用戶:))
除此之外,網絡設備可以強制關閉連接(例如具有預先配置的請求超時的負載平衡器)。
這就是為什么人們建議某種異步流程。
我可以說您仍然可以使用異步流,生成任務,並在每次批量更新一些共享 state(在單個實例的情況下在內存中)和持久性(如在集群的情況下的數據庫)。
這樣與客戶端的交互就會發生變化:
如果在事務執行過程中出現故障,則回滾完成,進程將數據庫狀態更新為“失敗”。
您還可以使用更現代的技術來通知服務器(例如 web sockets),但對於這個問題,它有點超出 scope 。
這里要考慮的另一件事:據我所知,處理 200000 個對象應該在 30 分鍾內完成,這對於現代 RDBMS 來說並沒有那么多。 當然,在不了解您的用例的情況下很難說出那里發生了什么,但也許您可以優化流程本身(使用批量操作,減少對數據庫的請求數量,緩存等等)。
在這些情況下,我首選的方法是使調用異步(Spring Boot 允許使用@Async
注釋進行此操作),因此客戶端不會期望任何 HTTP 響應。 通知可以通過 WebSocket 完成,它將向客戶端推送一條消息,其中包含每個 X 項目處理的進度。
當然,它會給您的應用程序增加更多復雜性,但是如果您正確設計該機制,您將能夠將其重用於您將來可能面臨的任何其他類似操作。
從技術角度來看,它可以通過org.springframework.transaction.annotation.Propagation#NESTED
傳播來完成,NESTED 行為使嵌套的 Spring 事務使用相同的物理事務,但在嵌套調用之間設置保存點,因此內部事務也可以獨立回滾外部事務,或者讓它們傳播。 但該限制僅適用於org.springframework.jdbc.datasource.DataSourceTransactionManager
數據源。
但是對於非常大的數據集,它仍然需要更多的時間來處理並使客戶端等待,所以從解決方案的角度來看,也許使用異步方法會更好,但這取決於您的要求。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.