<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【面試必問】| 哪些場景下Spring的事務(wù)會失效?

          共 5287字,需瀏覽 11分鐘

           ·

          2021-12-20 02:08


          源?/?? ? ? ??文/?冰河

          在日常工作中,如果對Spring的事務(wù)管理功能使用不當,則會造成Spring事務(wù)不生效的問題。而針對Spring事務(wù)不生效的問題,也是在跳槽面試中被問的比較頻繁的一個問題。
          今天,我們就一起梳理下有哪些場景會導(dǎo)致Spring事務(wù)生效。
          注:部分內(nèi)容引用自冰河與貓大人出版的
          深入理解分布式事務(wù):原理與實戰(zhàn)》一書。
          文章收錄于GitHub和Gitee:
          GitHub: https://github.com/sunshinelyz/technology-binghe
          Gitee: https://gitee.com/binghe001/technology-binghe

          Spring事務(wù)不生效總覽

          簡單來說,Spring事務(wù)會在幾種特定的場景下失效,如下圖所示。

          數(shù)據(jù)庫不支持事務(wù)

          Spring事務(wù)生效的前提是所連接的數(shù)據(jù)庫要支持事務(wù),如果底層的數(shù)據(jù)庫都不支持事務(wù),則Spring的事務(wù)肯定會失效。例如,如果使用的數(shù)據(jù)庫為MySQL,并且選用了MyISAM存儲引擎,則Spring的事務(wù)就會失效。

          事務(wù)方法未被Spring管理

          如果事務(wù)方法所在的類沒有加載到Spring IOC容器中,也就是說,事務(wù)方法所在的類沒有被Spring管理,則Spring事務(wù)會失效,示例如下。
          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容器中,就會造成updateProductStockCountById()方法的事務(wù)在Spring中失效。

          方法沒有被public修飾

          如果事務(wù)所在的方法沒有被public修飾,此時Spring的事務(wù)會失效,例如,如下代碼所示。
          @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()方法為內(nèi)部的私有方法(使用private修飾),那么此時updateProductStockCountById()方法的事務(wù)在Spring中會失效。

          同一類中方法調(diào)用

          如果同一個類中的兩個方法分別為A和B,方法A上沒有添加事務(wù)注解,方法B上添加了 @Transactional事務(wù)注解,方法A調(diào)用方法B,則方法B的事務(wù)會失效。例如,如下代碼所示。
          @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()方法上沒有標注事務(wù)注解,updateProductStockCountById()方法上標注了事務(wù)注解,submitOrder()方法調(diào)用了updateProductStockCountById()方法,此時,updateProductStockCountById()方法的事務(wù)在Spring中會失效。

          未配置事務(wù)管理器

          如果在項目中沒有配置Spring的事務(wù)管理器,即使使用了Spring的事務(wù)管理功能,Spring的事務(wù)也不會生效。
          例如,沒有在項目的配置類中配置如下代碼。
          @Bean
          public?PlatformTransactionManager?transactionManager(DataSource?dataSource)?{
          ?return?new?DataSourceTransactionManager(dataSource);
          }
          此時,Spring的事務(wù)就會失效。

          方法的事務(wù)傳播類型不支持事務(wù)

          如果內(nèi)部方法的事務(wù)傳播類型為不支持事務(wù)的傳播類型,則內(nèi)部方法的事務(wù)在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()方法的事務(wù)傳播類型為NOT_SUPPORTED,不支持事務(wù),則updateProductStockCountById()方法的事務(wù)會在Spring中失效。

          不正確的捕獲異常

          不正確的捕獲異常也會導(dǎo)致Spring的事務(wù)失效,示例如下。
          @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()方法內(nèi)部會拋出異常,但也會被catch代碼塊捕獲到,此時updateProductStockCountById()方法的事務(wù)會提交而不會回滾,并且submitOrder()方法的事務(wù)會提交而不會回滾,這就造成了Spring事務(wù)的回滾失效問題。

          錯誤的標注異常類型

          如果在@Transactional注解中標注了錯誤的異常類型,則Spring事務(wù)的回滾會失效,示例如下。
          @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()方法中捕獲了異常,并且在異常中拋出了Exception類型的異常,此時,updateProductStockCountById()方法事務(wù)的回滾會失效。
          為何會失效呢?這是因為Spring中對于默認回滾的事務(wù)異常類型為RuntimeException,上述代碼拋出的是Exception異常。
          默認情況下,Spring事務(wù)中無法捕獲到Exception異常,所以此時updateProductStockCountById()方法事務(wù)的回滾會失效。
          此時可以手動指定updateProductStockCountById()方法標注的事務(wù)異常類型,如下所示。
          @Transactional(propagation?=?Propagation.REQUIRED,rollbackFor?=?Exception.class)
          這里,需要注意的是:Spring事務(wù)注解@Transactional中的rollbackFor屬性可以指定 Throwable 異常類及其子類。


          END


          頂級程序員:topcoding

          做最好的程序員社區(qū):Java后端開發(fā)、Python、大數(shù)據(jù)、AI


          一鍵三連「分享」、「點贊」和「在看」


          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品久久久久无码AV铜川 | 国产一区在线播放 | 综合网激情 | 九色国产 | 欧美精品A片在线观看报备 |