<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    【面試必問(wèn)】| 哪些場(chǎng)景下Spring的事務(wù)會(huì)失效?

    共 5287字,需瀏覽 11分鐘

     ·

    2021-12-20 02:08


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

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

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

    簡(jiǎn)單來(lái)說(shuō),Spring事務(wù)會(huì)在幾種特定的場(chǎng)景下失效,如下圖所示。

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

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

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

    如果事務(wù)方法所在的類(lèi)沒(méi)有加載到Spring IOC容器中,也就是說(shuō),事務(wù)方法所在的類(lèi)沒(méi)有被Spring管理,則Spring事務(wù)會(huì)失效,示例如下。
    public?class?ProductService?{
    ?@Autowired
    ?private?ProductDao?productDao;

    ?@Transactional(propagation?=?Propagation.REQUIRES_NEW)
    ?public?void?updateProductStockCountById(Integer?stockCount,?Long?id){
    ??productDao.updateProductStockCountById(stockCount,?id);
    ?}
    }
    ProductService類(lèi)上沒(méi)有標(biāo)注@Service注解,Product的實(shí)例沒(méi)有加載到Spring IOC容器中,就會(huì)造成updateProductStockCountById()方法的事務(wù)在Spring中失效。

    方法沒(méi)有被public修飾

    如果事務(wù)所在的方法沒(méi)有被public修飾,此時(shí)Spring的事務(wù)會(huì)失效,例如,如下代碼所示。
    @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上標(biāo)注了@Service注解,同時(shí)updateProductStockCountById()方法上標(biāo)注了@Transactional(propagation = Propagation.REQUIRES_NEW)注解。
    但是,由于updateProductStockCountById()方法為內(nèi)部的私有方法(使用private修飾),那么此時(shí)updateProductStockCountById()方法的事務(wù)在Spring中會(huì)失效。

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

    如果同一個(gè)類(lèi)中的兩個(gè)方法分別為A和B,方法A上沒(méi)有添加事務(wù)注解,方法B上添加了 @Transactional事務(wù)注解,方法A調(diào)用方法B,則方法B的事務(wù)會(huì)失效。例如,如下代碼所示。
    @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);
    ??//減庫(kù)存
    ??this.updateProductStockCountById(1,?1L);
    ?}

    ?@Transactional(propagation?=?Propagation.REQUIRES_NEW)
    ?public?void?updateProductStockCountById(Integer?stockCount,?Long?id){
    ??productDao.updateProductStockCountById(stockCount,?id);
    ?}
    }
    submitOrder()方法和updateProductStockCountById()方法都在OrderService類(lèi)中,submitOrder()方法上沒(méi)有標(biāo)注事務(wù)注解,updateProductStockCountById()方法上標(biāo)注了事務(wù)注解,submitOrder()方法調(diào)用了updateProductStockCountById()方法,此時(shí),updateProductStockCountById()方法的事務(wù)在Spring中會(huì)失效。

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

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

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

    如果內(nèi)部方法的事務(wù)傳播類(lèi)型為不支持事務(wù)的傳播類(lèi)型,則內(nèi)部方法的事務(wù)在Spring中會(huì)失效。
    例如,如下代碼所示。
    @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);
    ??//減庫(kù)存
    ??this.updateProductStockCountById(1,?1L);
    ?}

    ?@Transactional(propagation?=?Propagation.NOT_SUPPORTED)
    ?public?void?updateProductStockCountById(Integer?stockCount,?Long?id){
    ??productDao.updateProductStockCountById(stockCount,?id);
    ?}
    }
    由于updateProductStockCountById()方法的事務(wù)傳播類(lèi)型為NOT_SUPPORTED,不支持事務(wù),則updateProductStockCountById()方法的事務(wù)會(huì)在Spring中失效。

    不正確的捕獲異常

    不正確的捕獲異常也會(huì)導(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);
    ??//減庫(kù)存
    ??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("扣減庫(kù)存異常:",?e.getMesaage());
    ??}
    ?}
    }
    updateProductStockCountById()方法中使用try-catch代碼塊捕獲了異常,即使updateProductStockCountById()方法內(nèi)部會(huì)拋出異常,但也會(huì)被catch代碼塊捕獲到,此時(shí)updateProductStockCountById()方法的事務(wù)會(huì)提交而不會(huì)回滾,并且submitOrder()方法的事務(wù)會(huì)提交而不會(huì)回滾,這就造成了Spring事務(wù)的回滾失效問(wèn)題。

    錯(cuò)誤的標(biāo)注異常類(lèi)型

    如果在@Transactional注解中標(biāo)注了錯(cuò)誤的異常類(lèi)型,則Spring事務(wù)的回滾會(huì)失效,示例如下。
    @Transactional(propagation?=?Propagation.REQUIRED)
    public?void?updateProductStockCountById(Integer?stockCount,?Long?id){
    ?try{
    ??productDao.updateProductStockCountById(stockCount,?id);
    ?}catch(Exception?e){
    ??logger.error("扣減庫(kù)存異常:",?e.getMesaage());
    ??throw?new?Exception("扣減庫(kù)存異常");
    ?}
    }
    在updateProductStockCountById()方法中捕獲了異常,并且在異常中拋出了Exception類(lèi)型的異常,此時(shí),updateProductStockCountById()方法事務(wù)的回滾會(huì)失效。
    為何會(huì)失效呢?這是因?yàn)镾pring中對(duì)于默認(rèn)回滾的事務(wù)異常類(lèi)型為RuntimeException,上述代碼拋出的是Exception異常。
    默認(rèn)情況下,Spring事務(wù)中無(wú)法捕獲到Exception異常,所以此時(shí)updateProductStockCountById()方法事務(wù)的回滾會(huì)失效。
    此時(shí)可以手動(dòng)指定updateProductStockCountById()方法標(biāo)注的事務(wù)異常類(lèi)型,如下所示。
    @Transactional(propagation?=?Propagation.REQUIRED,rollbackFor?=?Exception.class)
    這里,需要注意的是:Spring事務(wù)注解@Transactional中的rollbackFor屬性可以指定 Throwable 異常類(lèi)及其子類(lèi)。


    END


    頂級(jí)程序員:topcoding

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


    一鍵三連「分享」、「點(diǎn)贊」和「在看」


    瀏覽 52
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    国产无码精品毛片 | 无码精品一区二区三区四区五区六区 | 麻豆精品A∨在线观看 | 天天日,天天干,天天操 | 无码超碰 |