4 回答
TA貢獻1803條經(jīng)驗 獲得超3個贊
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);
}
}
如果此方法位于同一服務(wù)中,則@Transactional原始方法updateSharedStateByCommunity不會執(zhí)行任何操作,因此它會起作用。如果您將此代碼放入其他類中,那么它將起作用,因為 spring 事務(wù)的默認傳播級別是“必需”
因此它滿足了苛刻的要求:您想要進行一次交易 - 您已經(jīng)做到了?,F(xiàn)在所有代碼都在同一個事務(wù)中運行?,F(xiàn)在每個方法都使用 100000 個 ID 運行,而不是使用所有 id,一切都是同步的:)
然而,這種設(shè)計由于許多不同的原因而存在問題。
正如您在問題的最后一句中所說,它不允許跟蹤進度(向用戶顯示)。REST 是同步的。
它假設(shè)網(wǎng)絡(luò)是可靠的,并且等待 30 分鐘在技術(shù)上不是問題(不考慮 UX 和必須等待的“緊張”用戶:))
除此之外,網(wǎng)絡(luò)設(shè)備可以強制關(guān)閉連接(例如具有預(yù)先配置的請求超時的負載均衡器)。
這就是為什么人們建議某種異步流。
我可以說,您仍然可以使用異步流,生成任務(wù),并在每次批量更新后一些共享狀態(tài)(在單個實例的情況下在內(nèi)存中)和持久狀態(tài)(如集群情況下的數(shù)據(jù)庫)。
這樣與客戶端的交互就會改變:
客戶端使用 200000 個 id 調(diào)用“updateUser”
服務(wù)會“立即”響應(yīng),例如“我收到了您的請求,這是一個請求 ID,請偶爾對我進行 ping 操作,看看會發(fā)生什么情況。
服務(wù)啟動異步任務(wù)并在單個事務(wù)中逐塊處理數(shù)據(jù)
客戶端使用該 id 調(diào)用“get”方法,服務(wù)器從共享狀態(tài)讀取進度。
一旦準備好,“獲取”方法將響應(yīng)“完成”。
如果事務(wù)執(zhí)行期間出現(xiàn)故障,則回滾完成,并且進程將數(shù)據(jù)庫狀態(tài)更新為“失敗”。
您還可以使用更現(xiàn)代的技術(shù)來通知服務(wù)器(例如網(wǎng)絡(luò)套接字),但這超出了這個問題的范圍。
這里需要考慮的另一件事是:據(jù)我所知,處理 200000 個對象應(yīng)該在不到 30 分鐘的時間內(nèi)完成,對于現(xiàn)代 RDBMS 來說還不夠。當然,在不知道您的用例的情況下,很難判斷那里發(fā)生了什么,但也許您可以優(yōu)化流程本身(使用批量操作、減少對數(shù)據(jù)庫的請求數(shù)量、緩存等)。
TA貢獻1811條經(jīng)驗 獲得超5個贊
在這些場景中,我的首選方法是使調(diào)用異步(Spring Boot 允許使用注釋@Async),因此客戶端不會期望任何 HTTP 響應(yīng)。該通知可以通過 WebSocket 完成,該 WebSocket 將向客戶端推送一條消息,其中包含每個 X 項的處理進度。
當然,它會給您的應(yīng)用程序增加更多的復(fù)雜性,但如果您正確設(shè)計該機制,您將能夠?qū)⑵渲赜糜谀鷮砜赡苊媾R的任何其他類似操作。
TA貢獻1868條經(jīng)驗 獲得超4個贊
從技術(shù)角度來看,可以通過傳播來完成org.springframework.transaction.annotation.Propagation#NESTED,NESTED 行為使嵌套 Spring 事務(wù)使用相同的物理事務(wù),但在嵌套調(diào)用之間設(shè)置保存點,因此內(nèi)部事務(wù)也可以獨立于外部事務(wù)回滾,或者讓它們傳播。但限制僅適用于org.springframework.jdbc.datasource.DataSourceTransactionManager數(shù)據(jù)源。
但是對于非常大的數(shù)據(jù)集,它仍然需要更多的時間來處理并使客戶端等待,因此從解決方案的角度來看,也許使用異步方法會更好,但這取決于您的要求。
TA貢獻1784條經(jīng)驗 獲得超2個贊
該@Transactional注釋接受 atimeout(盡管并非所有底層實現(xiàn)都支持它)。我反對嘗試將 ID 拆分為兩個調(diào)用,而是嘗試修復(fù)超時(畢竟,您真正想要的是單個、全有或全無的事務(wù))。您可以為整個應(yīng)用程序設(shè)置超時,而不是針對每個方法設(shè)置超時。
添加回答
舉報
