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

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

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

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

大家好,我是飄渺。今天繼續DDD&微服務專欄。r6228資訊網——每日最新資訊28at.com

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

圖片圖片r6228資訊網——每日最新資訊28at.com

為什么會產生長事務

首先,讓我們來分析一下產生長事務的原因。r6228資訊網——每日最新資訊28at.com

在Spring中,@Transactional注解是基于AOP實現的,本質上是在目標方法執行前后進行攔截。在目標方法執行前加入或創建一個事務,在方法執行后,根據實際情況選擇提交或回滾事務。r6228資訊網——每日最新資訊28at.com

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

在開頭的實例中,一個事務中執行RPC操作是典型的長事務問題。類似的操作還包括在事務中進行大量數據查詢、業務規則處理等。r6228資訊網——每日最新資訊28at.com

長事務會產生哪些問題

長事務引發的常見危害有:r6228資訊網——每日最新資訊28at.com

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

如何避免長事務

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

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

編程式事務

因此,我們可以采用編程式事務替代聲明式事務@Transactional。在Spring項目中,可以注入TransactionTemplate對象,然后手動控制事務范圍。改造過后的代碼如下所示:r6228資訊網——每日最新資訊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發布了一個事件,讓監聽者來處理剩下的業務邏輯,(在Dailymart中創建訂單后需要進行庫存預扣),在默認情況下,Spring的事件監聽機制是同步的將代碼進行解耦,我們希望庫存扣減如果出現失敗需要回滾訂單,而編程式事務無法控制監聽者的事務。因此,在這種場景下并不適合使用編程式事務來處理。r6228資訊網——每日最新資訊28at.com

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

對方法進行拆分

另外一種常見的處理措施就是將方法進行拆分,將大方法拆成小方法,將不需要事務管理的邏輯與事務操作拆開。r6228資訊網——每日最新資訊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()分開。然而,這樣的簡單拆分會導致事務不生效。這又涉及到另一個知識點:r6228資訊網——每日最新資訊28at.com

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

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

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

  1. 將方法放入另一個類,如新增一個Manager層,通過Spring注入,這樣符合了在對象之間調用的條件。詳細說明可以參考我的文章為什么阿里建議給MVC三層架構再加一層Manager層!。
  2. 啟動類添加@EnableAspectJAutoProxy(exposeProxy = true),方法內使用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的分層架構模型實現。原來的業務邏輯是在應用服務編寫,在我們項目中只需要將保存訂單的邏輯放在領域服務層,由領域服務保證事務,而應用服務層負責組裝業務邏輯。最終代碼如下:r6228資訊網——每日最新資訊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));      }}

小結

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

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

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

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

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

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 龙江县| 沧州市| 新龙县| 东宁县| 从化市| 石狮市| 佳木斯市| 莒南县| 苏州市| 辽阳市| 济阳县| 外汇| 聊城市| 贵定县| 白山市| 萨迦县| 新乐市| 遂平县| 嵊州市| 武汉市| 镇雄县| 石屏县| 芷江| 江山市| 重庆市| 冀州市| 苏尼特右旗| 高平市| 阜阳市| 松溪县| 都昌县| 新乡县| 灯塔市| 正宁县| 自治县| 敦化市| 南郑县| 枣阳市| 丹凤县| 北辰区| 岑溪市|