日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Spring事務長了個腿?輕松掌握技巧告別長事務煩惱!

來源: 責編: 時間:2024-01-02 09:31:37 223觀看
導讀大家好,我是飄渺。今天繼續(xù)DDD&微服務專欄。在之前的文章 基于DDD的訂單創(chuàng)建 流程中,我們留下了一個問題:在createOrder()方法中,我將調(diào)用遠程接口獲取購物車詳情、遠程庫存校驗、訂單保存放在一個事務中,顯然這并不是一個

大家好,我是飄渺。今天繼續(xù)DDD&微服務專欄。laG28資訊網(wǎng)——每日最新資訊28at.com

在之前的文章 基于DDD的訂單創(chuàng)建 流程中,我們留下了一個問題:在createOrder()方法中,我將調(diào)用遠程接口獲取購物車詳情、遠程庫存校驗、訂單保存放在一個事務中,顯然這并不是一個正確的做法,因為它會導致長事務,今天就讓我們來解決這個問題。laG28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片laG28資訊網(wǎng)——每日最新資訊28at.com

為什么會產(chǎn)生長事務

首先,讓我們來分析一下產(chǎn)生長事務的原因。laG28資訊網(wǎng)——每日最新資訊28at.com

在Spring中,@Transactional注解是基于AOP實現(xiàn)的,本質(zhì)上是在目標方法執(zhí)行前后進行攔截。在目標方法執(zhí)行前加入或創(chuàng)建一個事務,在方法執(zhí)行后,根據(jù)實際情況選擇提交或回滾事務。laG28資訊網(wǎng)——每日最新資訊28at.com

當Spring遇到該注解時,會自動從數(shù)據(jù)庫連接池中獲取連接并開啟事務,然后綁定到ThreadLocal上,對于@Transactional注解包裹的整個方法都是使用同一個連接。如果出現(xiàn)耗時的操作,如第三方接口調(diào)用、業(yè)務邏輯復雜、大批量數(shù)據(jù)處理等,就會導致占用連接的時間很長,數(shù)據(jù)庫連接一直被占用不釋放。一旦類似操作過多,就會導致數(shù)據(jù)庫連接池耗盡。laG28資訊網(wǎng)——每日最新資訊28at.com

在開頭的實例中,一個事務中執(zhí)行RPC操作是典型的長事務問題。類似的操作還包括在事務中進行大量數(shù)據(jù)查詢、業(yè)務規(guī)則處理等。laG28資訊網(wǎng)——每日最新資訊28at.com

長事務會產(chǎn)生哪些問題

長事務引發(fā)的常見危害有:laG28資訊網(wǎng)——每日最新資訊28at.com

  1. 數(shù)據(jù)庫連接池被占滿,應用無法獲取連接資源;
  2. 容易引發(fā)數(shù)據(jù)庫死鎖;
  3. 數(shù)據(jù)庫回滾時間長;
  4. 在主從架構(gòu)中會導致主從延時變大。

如何避免長事務

既然知道了長事務的危害,那么在開發(fā)中如何避免這個問題呢?laG28資訊網(wǎng)——每日最新資訊28at.com

很明顯,解決長事務的宗旨就是 對事務方法進行拆分,盡量讓事務變小,變快,減小事務的顆粒度。laG28資訊網(wǎng)——每日最新資訊28at.com

編程式事務

因此,我們可以采用編程式事務替代聲明式事務@Transactional。在Spring項目中,可以注入TransactionTemplate對象,然后手動控制事務范圍。改造過后的代碼如下所示:laG28資訊網(wǎng)——每日最新資訊28at.com

public String createOrder(OrderCreateRequest orderCreateRequest) { // 獲取購物車詳情 ShoppingCartDetailDTO shoppingCartDetailDTO = cartRemoteFacade.queryCheckedCartItemByUserId(orderCreateRequest.getCustomerId()); List<CartItemDTO> cartItemList = shoppingCartDetailDTO.getCartItemDtoS(); //校驗庫存 checkInventory(cartItemList); ...  transactionTemplate.executeWithoutResult(status -> {       orderRepository.save(tradeOrder);  eventPublisher.publishEvent(new OrderCreatedEvent(tradeOrder));  }); return orderSn;}

然而,這里涉及到另一個問題:在保存訂單后我們通過EventPublisher發(fā)布了一個事件,讓監(jiān)聽者來處理剩下的業(yè)務邏輯,(在Dailymart中創(chuàng)建訂單后需要進行庫存預扣),在默認情況下,Spring的事件監(jiān)聽機制是同步的將代碼進行解耦,我們希望庫存扣減如果出現(xiàn)失敗需要回滾訂單,而編程式事務無法控制監(jiān)聽者的事務。因此,在這種場景下并不適合使用編程式事務來處理。laG28資訊網(wǎng)——每日最新資訊28at.com

敲黑板:使用編程式事務替代聲明式事務是解決長事務最簡單的實現(xiàn)方式,在大部分場景下都可以采用。在使用時要注意編程式事務搭配EventPublisher時無法控制監(jiān)聽者的事務。laG28資訊網(wǎng)——每日最新資訊28at.com

對方法進行拆分

另外一種常見的處理措施就是將方法進行拆分,將大方法拆成小方法,將不需要事務管理的邏輯與事務操作拆開。laG28資訊網(wǎng)——每日最新資訊28at.com

public String createOrder(OrderCreateRequest orderCreateRequest) { // 獲取購物車詳情 ShoppingCartDetailDTO shoppingCartDetailDTO = cartRemoteFacade.queryCheckedCartItemByUserId(orderCreateRequest.getCustomerId()); List<CartItemDTO> cartItemList = shoppingCartDetailDTO.getCartItemDtoS(); //校驗庫存 checkInventory(cartItemList); ...  this.saveOrder(tradeOrder) return orderSn;}@Transactional(rollbackFor = RuntimeException.class)private void saveOrder(TradeOrder tradeOrder){ orderRepository.save(tradeOrder); eventPublisher.publishEvent(new OrderCreatedEvent(tradeOrder)); }

在上述代碼中,獲取購物車詳情與庫存校驗不需要事務,將其與事務方法saveOrder()分開。然而,這樣的簡單拆分會導致事務不生效。這又涉及到另一個知識點:laG28資訊網(wǎng)——每日最新資訊28at.com

@Transactional注解的聲明式事務是通過spring aop起作用的,而spring aop需要生成代理對象,直接在同一個類中方法調(diào)用使用的還是原始對象,事務不生效。其他幾個常見的事務不生效的場景為:laG28資訊網(wǎng)——每日最新資訊28at.com

  • @Transactional 應用在非 public 修飾的方法上
  • @Transactional 注解屬性 propagation 設置錯誤
  • @Transactional 注解屬性 rollbackFor 設置錯誤
  • 同一個類中方法調(diào)用,導致@Transactional失效
  • 異常被catch捕獲導致@Transactional失效

正確的拆分方法應該使用下面兩種:laG28資訊網(wǎng)——每日最新資訊28at.com

  1. 將方法放入另一個類,如新增一個Manager層,通過Spring注入,這樣符合了在對象之間調(diào)用的條件。詳細說明可以參考我的文章為什么阿里建議給MVC三層架構(gòu)再加一層Manager層!。
  2. 啟動類添加@EnableAspectJAutoProxy(exposeProxy = true),方法內(nèi)使用AopContext.currentProxy()獲得代理類,使用事務。
SpringBootApplication.java    @EnableAspectJAutoProxy(exposeProxy = true)  @SpringBootApplication  public class SpringBootApplication {}public String createOrder(OrderCreateRequest orderCreateRequest) { ... OrderService orderService = (OrderService)AopContext.currentProxy();     orderService.saveData(tradeOrder);   return orderSn;}@Transactional(rollbackFor = RuntimeException.class)private void saveOrder(TradeOrder tradeOrder){ orderRepository.save(tradeOrder); eventPublisher.publishEvent(new OrderCreatedEvent(tradeOrder)); }

然而,Dailymart項目是基于DDD的分層架構(gòu)模型實現(xiàn)。原來的業(yè)務邏輯是在應用服務編寫,在我們項目中只需要將保存訂單的邏輯放在領域服務層,由領域服務保證事務,而應用服務層負責組裝業(yè)務邏輯。最終代碼如下:laG28資訊網(wǎng)——每日最新資訊28at.com

private final TradeOrderService tradeOrderService;@Override  // @Transactional(rollbackFor = RuntimeException.class)  public String createOrder(OrderCreateRequest orderCreateRequest) {      // 生成訂單編號      String orderSn = IdUtils.nextIdStr();      // 獲取購物車詳情      ShoppingCartDetailDTO shoppingCartDetailDTO = cartRemoteFacade.queryCheckedCartItemByUserId(orderCreateRequest.getCustomerId());      List<CartItemDTO> cartItemList = shoppingCartDetailDTO.getCartItemDtoS();            // 校驗庫存      checkInventory(cartItemList);   ...          tradeOrderService.save(tradeOrder);     return orderSn;  }@Service  @RequiredArgsConstructor(onConstructor = @__(@Autowired))  public class TradeOrderServiceImpl implements TradeOrderService {            private final ApplicationEventPublisher eventPublisher;            private final OrderRepository orderRepository;            @Override      @Transactional        public void save(TradeOrder tradeOrder) {          orderRepository.save(tradeOrder);          eventPublisher.publishEvent(new OrderCreatedEvent(tradeOrder));      }}

小結(jié)

本文討論了長事務的危害及解決方案。首先,我們探討了長事務導致的問題,包括數(shù)據(jù)庫連接池耗盡、死鎖等。其次,介紹了兩種解決策略:采用編程式事務和對方法進行拆分。編程式事務提供了手動控制事務范圍的方式,但需要注意搭配EventPublisher可能導致監(jiān)聽者事務無法控制的問題。對方法進行拆分是一種更通用的方法,能夠減小事務范圍,提高執(zhí)行效率。最后,通過實際的DDD分層架構(gòu)示例,展示了在應用服務層和領域服務層中如何組織業(yè)務邏輯,確保事務正確性和性能。laG28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-55265-0.htmlSpring事務長了個腿?輕松掌握技巧告別長事務煩惱!

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 淺談ArkUI之Web組件的基礎用法

下一篇: Spring事務長了個腿?輕松掌握技巧告別長事務煩惱!

標簽:
  • 熱門焦點
  • 紅魔電競平板評測:大屏幕硬實力

    前言:三年的疫情因為要上網(wǎng)課的原因激活了平板市場,如今網(wǎng)課的時代已經(jīng)過去,大家的生活都恢復到了正軌,這也就意味著,真正考驗平板電腦生存的環(huán)境來了。也就是面對著這種殘酷的
  • 2023年Q2用戶偏好榜:12+256G版本成新主流

    3月份的性能榜、性價比榜和好評榜之后,就要輪到2023年的第二季度偏好榜了,上半年的新機潮已經(jīng)過去,最明顯的肯定就是大內(nèi)存和存儲的機型了,另外部分中端機也取消了屏幕塑料支架
  • 0糖0卡0脂 旭日森林仙草烏龍茶優(yōu)惠:15瓶到手29元

    旭日森林無糖仙草烏龍茶510ml*15瓶平時要賣為79.9元,今日下單領取50元優(yōu)惠券,到手價為29.9元。產(chǎn)品規(guī)格:0糖0卡0脂,添加草本仙草汁,清涼爽口,富含茶多酚,保留
  • 2023 年的 Node.js 生態(tài)系統(tǒng)

    隨著技術(shù)的不斷演進和創(chuàng)新,Node.js 在 2023 年達到了一個新的高度。Node.js 擁有一個龐大的生態(tài)系統(tǒng),可以幫助開發(fā)人員更快地實現(xiàn)復雜的應用。本文就來看看 Node.js 最新的生
  • 一篇文章帶你了解 CSS 屬性選擇器

    屬性選擇器對帶有指定屬性的 HTML 元素設置樣式。可以為擁有指定屬性的 HTML 元素設置樣式,而不僅限于 class 和 id 屬性。一、了解屬性選擇器CSS屬性選擇器提供了一種簡單而
  • 為什么你不應該使用Div作為可點擊元素

    按鈕是為任何網(wǎng)絡應用程序提供交互性的最常見方式。但我們經(jīng)常傾向于使用其他HTML元素,如 div span 等作為 clickable 元素。但通過這樣做,我們錯過了許多內(nèi)置瀏覽器的功能。
  • 東方甄選單飛:有些鳥注定是關(guān)不住的

    作者:彭寬鴻來源:華爾街科技眼&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;東方甄選創(chuàng)始人俞敏洪帶隊的&ldquo;7天甘肅行&rdquo;直播活動已在近日順利收官。成立后一
  • 8月見!小米MIX Fold 3獲得3C認證:支持67W快充

    這段時間以來,包括三星、一加、榮耀等等有不少品牌旗下的最新折疊屏旗艦都得到了不少爆料,而小米新一代折疊屏旗艦——小米MIX Fold 3此前也屢屢被傳
  • 三星Galaxy Z Fold/Flip 5國行售價曝光 :最低7499元/12999元起

    據(jù)官方此前宣布,三星將于7月26日也就是明天在韓國首爾舉辦Unpacked活動,屆時將帶來帶來包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy
Top 主站蜘蛛池模板: 桐城市| 永济市| 巴林左旗| 高台县| 黄浦区| 东光县| 巫山县| 凤冈县| 濮阳县| 绥滨县| 屏东县| 名山县| 呼伦贝尔市| 廉江市| 榆树市| 开平市| 文水县| 定陶县| 西乡县| 怀来县| 南溪县| 星座| 哈密市| 舟山市| 新建县| 什邡市| 重庆市| 香港 | 绥芬河市| 樟树市| 南溪县| 淅川县| 武功县| 安康市| 罗定市| 衡南县| 乌兰浩特市| 昌江| 江门市| 通化县| 尼玛县|