インタビューの質問|Springのトランザクションはどのシナリオで失敗しますか?

みなさん、こんにちは。氷河です~~

日常業務において、Springのトランザクション管理機能を不適切に使用すると、Springトランザクションが有効にならないという問題が発生します。春の取引が有効にならないという問題は、転職の面接でよく聞かれる質問でもあります。

今日は、Springトランザクションが有効になるシナリオを整理しましょう。

注:コンテンツの一部は、 Glacier and Catが発行した「分散トランザクションの詳細な理解:原則と実践」という本から引用されています。

記事はGitHubとGiteeに含まれています:

GitHub:https://github.com/sunshinelyz/technology-binghe

Gitee:https://gitee.com/binghe001/technology-binghe

有効にならないSpringトランザクションの概要

つまり、次の図に示すように、Springトランザクションはいくつかの特定のシナリオで失敗します。

写真

データベースはトランザクションをサポートしていません

Springトランザクションが有効になるための前提条件は、接続されたデータベースがトランザクションをサポートしていることです。基盤となるデータベースがトランザクションをサポートしていない場合、Springトランザクションは確実に失敗します。たとえば、使用されているデータベースがMySQLであり、MyISAMストレージエンジンが選択されている場合、Springのトランザクションは失敗します。

トランザクションメソッドはSpringによって管理されていません

トランザクションメソッドが配置されているクラスがSpringIOCコンテナにロードされていない場合、つまりトランザクションメソッドが配置されているクラスがSpringによって管理されていない場合、Springトランザクションは失敗します。例は次のとおりです。

public class ProductService {
    
    
 @Autowired
 private ProductDao productDao;

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void updateProductStockCountById(Integer stockCount, Long id){
    
    
  productDao.updateProductStockCountById(stockCount, id);
 }
}

ProductServiceクラスには@Serviceアノテーションがなく、ProductのインスタンスがSpring IOCコンテナーにロードされないため、SpringでupdateProductStockCountById()メソッドのトランザクションが失敗します。

メソッドはパブリックによって変更されません

トランザクションが配置されているメソッドがpublicによって変更されていない場合、たとえば次のコードに示すように、Springのトランザクションは無効になります。

@Service
public class ProductService {
    
    
 @Autowired
 private ProductDao productDao;

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 private void updateProductStockCountById(Integer stockCount, Long id){
    
    
  productDao.updateProductStockCountById(stockCount, id);
 }
}

ProductServiceは@Serviceアノテーションでマークされていますが、updateProductStockCountById()メソッドは@Transactional(propagation = Propagation.REQUIRES_NEW)アノテーションでマークされています。

ただし、updateProductStockCountById()メソッドは内部プライベートメソッド(privateで変更)であるため、現時点では、updateProductStockCountById()メソッドのトランザクションはSpringでは無効になります。

同じクラスのメソッド呼び出し

同じクラスの2つのメソッドがAとBの場合、トランザクションアノテーションはメソッドAに追加されず、@ TransactionalトランザクションアノテーションがメソッドBに追加され、メソッドAがメソッドBを呼び出すと、メソッドBのトランザクションは無効になります。たとえば、次のコードに示すように。

@Service
public class OrderService {
    
    

 @Autowired
 private OrderDao orderDao;

 @Autowired
 private ProductDao productDao;

 public void submitOrder(){
    
    
  //生成订单
  Order order = new Order();
  long number = Math.abs(new Random().nextInt(500));
  order.setId(number);
  order.setOrderNo("order_" + number);
  orderDao.saveOrder(order);
  //减库存
  this.updateProductStockCountById(1, 1L);
 }

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void updateProductStockCountById(Integer stockCount, Long id){
    
    
  productDao.updateProductStockCountById(stockCount, id);
 }
}

submitOrder()メソッドとupdateProductStockCountById()メソッドはどちらもOrderServiceクラスにあります。submitOrder()メソッドはトランザクションアノテーションでマークされておらず、updateProductStockCountById()メソッドはトランザクションアノテーションでマークされています。submitOrder()メソッドはupdateProductStockCountByIdを呼び出します。 ()メソッド。現時点では、updateProductStockCountById()メソッドトランザクションはSpringで無効になっています。

トランザクションマネージャーが構成されていません

プロジェクトでSpringのトランザクションマネージャーが構成されていない場合、Springのトランザクション管理機能を使用しても、Springのトランザクションは有効になりません。

たとえば、次のコードはプロジェクトの構成クラスで構成されていません。

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    
    
 return new DataSourceTransactionManager(dataSource);
}

この時点で、Springのトランザクションは無効になります。

メソッドのトランザクション伝播タイプはトランザクションをサポートしていません

内部メソッドのトランザクション伝播タイプがトランザクションをサポートしない伝播タイプである場合、内部メソッドのトランザクションはSpringでは無効になります。

たとえば、次のコードに示すように。

@Service
public class OrderService {
    
    
 @Autowired
 private OrderDao orderDao;
 @Autowired
 private ProductDao productDao;

 @Transactional(propagation = Propagation.REQUIRED)
 public void submitOrder(){
    
    
  //生成订单
  Order order = new Order();
  long number = Math.abs(new Random().nextInt(500));
  order.setId(number);
  order.setOrderNo("order_" + number);
  orderDao.saveOrder(order);
  //减库存
  this.updateProductStockCountById(1, 1L);
 }

 @Transactional(propagation = Propagation.NOT_SUPPORTED)
 public void updateProductStockCountById(Integer stockCount, Long id){
    
    
  productDao.updateProductStockCountById(stockCount, id);
 }
}

updateProductStockCountById()メソッドのトランザクション伝播タイプはNOT_SUPPORTEDであり、トランザクションをサポートしていないため、updateProductStockCountById()メソッドのトランザクションはSpringでは無効になります。

誤ってキャッチされた例外

以下に示すように、誤ってキャッチされた例外により、Springのトランザクションが失敗する可能性もあります。

@Service
public class OrderService {
    
    
 @Autowired
 private OrderDao orderDao;
 @Autowired
 private ProductDao productDao;


 @Transactional(propagation = Propagation.REQUIRED)
 public void submitOrder(){
    
    
  //生成订单
  Order order = new Order();
  long number = Math.abs(new Random().nextInt(500));
  order.setId(number);
  order.setOrderNo("order_" + number);
  orderDao.saveOrder(order);
  //减库存
  this.updateProductStockCountById(1, 1L);
 }

 @Transactional(propagation = Propagation.REQUIRED)
 public void updateProductStockCountById(Integer stockCount, Long id){
    
    
  try{
    
    
   productDao.updateProductStockCountById(stockCount, id);
   int i = 1 / 0;
  }catch(Exception e){
    
    
   logger.error("扣减库存异常:", e.getMesaage());
  }
 }
}

updateProductStockCountById()メソッドでtry-catchコードブロックを使用して例外をキャッチします。updateProductStockCountById()メソッド内で例外がスローされた場合でも、catchコードブロックによってキャッチされます。このとき、 updateProductStockCountById()メソッドは、ロールバックを返さずにコミットされ、submitOrder()メソッドのトランザクションはコミットされますが、ロールバックされないため、Springトランザクションのロールバックが失敗します。

間違った注釈例外タイプ

@Transactionalアノテーションで間違った例外タイプがマークされている場合、Springトランザクションのロールバックは無効になります。例は次のとおりです。

@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
    
    
 try{
    
    
  productDao.updateProductStockCountById(stockCount, id);
 }catch(Exception e){
    
    
  logger.error("扣减库存异常:", e.getMesaage());
  throw new Exception("扣减库存异常");
 }
}

例外はupdateProductStockCountById()メソッドでキャッチされ、例外タイプの例外が例外でスローされます。この時点で、updateProductStockCountById()メソッドのトランザクションロールバックは無効になります。

なぜ失敗するのですか?これは、Springのデフォルトのロールバックのトランザクション例外タイプがRuntimeExceptionであり、上記のコードが例外例外をスローするためです。

デフォルトでは、例外例外はSpringトランザクションでキャッチできないため、updateProductStockCountById()メソッドでのトランザクションのロールバックは無効になります。

この時点で、次に示すように、updateProductStockCountById()メソッドでマークされたトランザクション例外タイプを手動で指定できます。

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)

ここで、Springトランザクションアノテーション@TransactionalのrollbackFor属性は、Throwable例外クラスとそのサブクラスを指定できることに注意してください。

さて、今日はここでやめましょう、私は氷河です、また会いましょう~~

最後に書く

大きな工場に参入したい、昇進や昇給をしたい、または現在の仕事について混乱している場合は、私にメッセージを送って連絡することができます。私の経験のいくつかがあなたに役立つことを願っています~~

推奨読書:

さて、今日ここで立ち止まって、友達、いいね、お気に入り、コメント、そしてワンクリックで歩き始めましょう、私は氷河です、次の号でお会いしましょう~~

おすすめ

転載: blog.csdn.net/l1028386804/article/details/124471028