成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發(fā) 前端
本文討論了長事務的危害及解決方案。首先,我們探討了長事務導致的問題,包括數(shù)據(jù)庫連接池耗盡、死鎖等。其次,介紹了兩種解決策略:采用編程式事務和對方法進行拆分。

大家好,我是飄渺。今天繼續(xù)DDD&微服務專欄。

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

圖片圖片

為什么會產生長事務

首先,讓我們來分析一下產生長事務的原因。

在Spring中,@Transactional注解是基于AOP實現(xiàn)的,本質上是在目標方法執(zhí)行前后進行攔截。在目標方法執(zhí)行前加入或創(chuàng)建一個事務,在方法執(zhí)行后,根據(jù)實際情況選擇提交或回滾事務。

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

在開頭的實例中,一個事務中執(zhí)行RPC操作是典型的長事務問題。類似的操作還包括在事務中進行大量數(shù)據(jù)查詢、業(yè)務規(guī)則處理等。

長事務會產生哪些問題

長事務引發(fā)的常見危害有:

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

如何避免長事務

既然知道了長事務的危害,那么在開發(fā)中如何避免這個問題呢?

很明顯,解決長事務的宗旨就是 對事務方法進行拆分,盡量讓事務變小,變快,減小事務的顆粒度。

編程式事務

因此,我們可以采用編程式事務替代聲明式事務@Transactional。在Spring項目中,可以注入TransactionTemplate對象,然后手動控制事務范圍。改造過后的代碼如下所示:

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)聽者的事務。因此,在這種場景下并不適合使用編程式事務來處理。

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

對方法進行拆分

另外一種常見的處理措施就是將方法進行拆分,將大方法拆成小方法,將不需要事務管理的邏輯與事務操作拆開。

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()分開。然而,這樣的簡單拆分會導致事務不生效。這又涉及到另一個知識點:

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

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

正確的拆分方法應該使用下面兩種:

  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的分層架構模型實現(xiàn)。原來的業(yè)務邏輯是在應用服務編寫,在我們項目中只需要將保存訂單的邏輯放在領域服務層,由領域服務保證事務,而應用服務層負責組裝業(yè)務邏輯。最終代碼如下:

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));  
    }
}

小結

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

責任編輯:武曉燕 來源: JAVA日知錄
相關推薦

2023-05-12 08:02:43

分布式事務應用

2009-11-11 09:31:44

ADO.NET事務處理

2020-12-30 15:06:39

開發(fā)技能代碼

2024-04-10 08:59:39

SpringAOP業(yè)務

2009-12-10 11:02:44

PHP函數(shù)eval()

2009-06-22 09:01:57

Spring聲明式事務

2024-12-02 08:37:04

2010-01-14 13:59:01

2009-12-11 17:25:00

Grub突破root

2009-12-17 14:36:57

Ruby on Rai

2024-05-10 11:52:00

編程C++

2018-02-28 13:49:49

屏幕截取win 10瀏覽器

2023-10-30 07:36:19

Spring事務傳播機制

2024-12-17 16:44:22

Spring開發(fā)

2020-08-19 09:45:29

Spring數(shù)據(jù)庫代碼

2022-02-14 16:53:57

Spring項目數(shù)據(jù)庫

2021-10-29 07:49:22

Spring事務管理

2009-06-29 17:54:47

Spring事務隔離

2020-07-17 08:07:54

Spring數(shù)據(jù)庫事務

2021-09-07 09:26:13

Python 開發(fā)編程語言
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 色婷婷综合成人av | 精品自拍视频 | 成人欧美一区二区三区黑人孕妇 | 国产精品国产精品国产专区不卡 | 亚洲理论在线观看电影 | 中文字幕在线一区二区三区 | 欧美视频在线播放 | 亚洲一区二区三区在线视频 | 蜜桃毛片| 国产色网 | 国产精品久久久久久久久久免费 | 国内精品久久久久久影视8 最新黄色在线观看 | 国产欧美一级二级三级在线视频 | 久久久影院 | 亚洲精品电影网在线观看 | 中国一级特黄真人毛片免费观看 | 亚洲第1页 | 日本午夜精品 | 7777精品伊人久久精品影视 | 精品国产久| 国产一区二区三区网站 | 欧美中文字幕 | 日韩一级黄色片 | 国产在线观看福利 | 午夜性色a√在线视频观看9 | 激情久久网 | 久久久久1 | av喷水| 韩日视频在线观看 | 日韩一区二区三区视频 | 欧美一级片在线观看 | 免费久久精品视频 | 亚洲精品久久久久久国产精华液 | 色www精品视频在线观看 | 国产精品一区二区在线免费观看 | 国产乡下妇女做爰 | 亚洲精品视频观看 | 亚洲不卡在线观看 | 中文字幕日韩一区 | 伦理一区二区 | 999精品在线观看 |