亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

解決@Transaction注解導(dǎo)致動(dòng)態(tài)切換更改數(shù)據(jù)庫(kù)失效問題

 更新時(shí)間:2021年09月07日 09:57:34   作者:侖小杰  
這篇文章主要介紹了解決@Transaction注解導(dǎo)致動(dòng)態(tài)切換更改數(shù)據(jù)庫(kù)失效問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@Transaction注解導(dǎo)致動(dòng)態(tài)切換更改數(shù)據(jù)庫(kù)失效

使用場(chǎng)景

  • 給所有的Controller方法上加切點(diǎn)
  • 在@Before注解的方法里,根據(jù)http請(qǐng)求中攜帶的header,動(dòng)態(tài)切換數(shù)據(jù)源
  • 使用mybatis或者jpa執(zhí)行操作

遇到問題

當(dāng)給Controller方法加上@Transaction注解后,動(dòng)態(tài)切換數(shù)據(jù)源就失效了,原因是每次@Before注解的方法運(yùn)行之前,protected abstract Object determineCurrentLookupKey();就已經(jīng)運(yùn)行了,而這個(gè)方法是切換數(shù)據(jù)源的關(guān)鍵。

解決

其實(shí)也算不上解決,就是不要在Controller方法上加事務(wù)注解,非要加事務(wù),中間的Service層就不要省了。

@Transactional失效的場(chǎng)景及原理

1.@Transactional修飾的方法

為非public方法,這個(gè)時(shí)候@Transactional會(huì)實(shí)現(xiàn)。

失敗的原理是:@Transactional是基于動(dòng)態(tài)代理來實(shí)現(xiàn)的,非public的方法,他@Transactional的動(dòng)態(tài)代理對(duì)象信息為空,所以不能回滾。

2.在類內(nèi)部沒有添加@Transactional的方法

調(diào)用了@Transactional方法時(shí),當(dāng)你調(diào)用是,他也不會(huì)回滾

測(cè)試代碼如下

@Service
public class UserServiceImpl extends BaseServiceImpl<UserEntity> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    @Transactional
    public void insertOne() {
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername("Michael_C_2019");
        //插入到數(shù)據(jù)庫(kù)
        userMapper.insertSelective(userEntity);
        //手動(dòng)拋出異常
        throw new IndexOutOfBoundsException();
    }
    @Override
    public void saveOne() {
        insertOne();
    }
}

失敗的原理:@Transactional是基于動(dòng)態(tài)代理對(duì)象來實(shí)現(xiàn)的,而在類內(nèi)部的方法的調(diào)用是通過this關(guān)鍵字來實(shí)現(xiàn)的,沒有經(jīng)過動(dòng)態(tài)代理對(duì)象,所以事務(wù)回滾失效。

3.就是在@Transactional方法內(nèi)部捕獲了異常

沒有在catch代碼塊里面重新拋出異常,事務(wù)也不會(huì)回滾。

代碼如下:

@Override
    @Transactional
    public void insertOne() {
        try {
            UserEntity userEntity = new UserEntity();
            userEntity.setUsername("Michael_C_2019");
            //插入到數(shù)據(jù)庫(kù)
            userMapper.insertSelective(userEntity);
            //手動(dòng)拋出異常
            throw new IndexOutOfBoundsException();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        }
    }

所以在阿里巴巴的Java開發(fā)者手冊(cè)里面有明確規(guī)定,在 @Transactional的方法里面捕獲了異常,必須要手動(dòng)回滾,

代碼如下:

 @Override
    @Transactional
    public void insertOne() {
        try {
            UserEntity userEntity = new UserEntity();
            userEntity.setUsername("Michael_C_2019");
            //插入到數(shù)據(jù)庫(kù)
            userMapper.insertSelective(userEntity);
            //手動(dòng)拋出異常
            throw new IndexOutOfBoundsException();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

失敗原理:這時(shí)候我們來看看spring的源碼:

TransactionAspectSupport類里面的invokeWithinTransaction方法

TransactionAspectSupport
@Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
        TransactionAttributeSource tas = this.getTransactionAttributeSource();
        TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
        PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
        String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
        Object result;
        if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
            TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder(null);
            try {
                result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, (status) -> {
                    TransactionAspectSupport.TransactionInfo txInfo = this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                    Object var9;
                    try {
                        Object var8 = invocation.proceedWithInvocation();
                        return var8;
                    } catch (Throwable var13) {
                        if (txAttr.rollbackOn(var13)) {
                            if (var13 instanceof RuntimeException) {
                                throw (RuntimeException)var13;
                            }
                            throw new TransactionAspectSupport.ThrowableHolderException(var13);
                        }
                        throwableHolder.throwable = var13;
                        var9 = null;
                    } finally {
                        this.cleanupTransactionInfo(txInfo);
                    }
                    return var9;
                });
                if (throwableHolder.throwable != null) {
                    throw throwableHolder.throwable;
                } else {
                    return result;
                }
            } catch (TransactionAspectSupport.ThrowableHolderException var19) {
                throw var19.getCause();
            } catch (TransactionSystemException var20) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    var20.initApplicationException(throwableHolder.throwable);
                }
                throw var20;
            } catch (Throwable var21) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }
                throw var21;
            }
        } else {
            TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            result = null;
            try {
                result = invocation.proceedWithInvocation();
            } catch (Throwable var17) {
              //異常時(shí),在catch邏輯中回滾事務(wù)
                this.completeTransactionAfterThrowing(txInfo, var17);
                throw var17;
            } finally {
                this.cleanupTransactionInfo(txInfo);
            }
            this.commitTransactionAfterReturning(txInfo);
            return result;
        }
    }

他是通過捕獲異常然后在catch里面進(jìn)行事務(wù)的回滾的,所以如果你在自己的方法里面catch了異常,catch里面沒有拋出新的異常,那么事務(wù)將不會(huì)回滾。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis的foreach語(yǔ)句詳解

    MyBatis的foreach語(yǔ)句詳解

    這篇文章主要介紹了MyBatis的foreach語(yǔ)句詳解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • Java設(shè)計(jì)模式之迭代器模式解析

    Java設(shè)計(jì)模式之迭代器模式解析

    這篇文章主要介紹了Java設(shè)計(jì)模式之迭代器模式解析,迭代器模式提供一個(gè)對(duì)象來順序訪問聚合對(duì)象中的一系列數(shù)據(jù),而不暴露聚合對(duì)象的內(nèi)部表示,本文提供了部分代碼,需要的朋友可以參考下
    2023-09-09
  • Java中StringBuilder與StringBuffer的區(qū)別

    Java中StringBuilder與StringBuffer的區(qū)別

    在Java編程中,字符串的拼接是一項(xiàng)常見的操作。為了有效地處理字符串的拼接需求,Java提供了兩個(gè)主要的類:StringBuilder和StringBuffer,本文主要介紹了Java中StringBuilder與StringBuffer的區(qū)別,感興趣的可以了解一下
    2023-08-08
  • 一篇文章帶你了解jdk1.8新特性--為什么使用lambda表達(dá)式

    一篇文章帶你了解jdk1.8新特性--為什么使用lambda表達(dá)式

    Lambda是一個(gè)匿名函數(shù),我們可以把Lambda表達(dá)式理解為是一段可以傳遞的代碼,本篇文章就帶你了解,希望能給你帶來幫助
    2021-08-08
  • Java定時(shí)器例子_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java定時(shí)器例子_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    本文給大家分享了java定時(shí)器例子,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧
    2017-05-05
  • Springboot啟用多個(gè)監(jiān)聽端口代碼實(shí)例

    Springboot啟用多個(gè)監(jiān)聽端口代碼實(shí)例

    這篇文章主要介紹了Springboot啟用多個(gè)監(jiān)聽端口代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java經(jīng)典面試題最全匯總208道(五)

    Java經(jīng)典面試題最全匯總208道(五)

    這篇文章主要介紹了Java經(jīng)典面試題最全匯總208道(五),本文章內(nèi)容詳細(xì),該模塊分為了六個(gè)部分,本次為第五部分,需要的朋友可以參考下
    2023-01-01
  • Java靜態(tài)代理與動(dòng)態(tài)代理案例詳解

    Java靜態(tài)代理與動(dòng)態(tài)代理案例詳解

    這篇文章主要介紹了Java靜態(tài)代理與動(dòng)態(tài)代理案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Java 線程死鎖的問題解決辦法

    Java 線程死鎖的問題解決辦法

    這篇文章主要介紹了 Java 線程死鎖的問題解決辦法的相關(guān)資料,希望通過本大家能幫助到大家,遇到類似問題能夠解決,需要的朋友可以參考下
    2017-09-09
  • SpringBoot快速搭建web項(xiàng)目詳細(xì)步驟總結(jié)

    SpringBoot快速搭建web項(xiàng)目詳細(xì)步驟總結(jié)

    這篇文章主要介紹了SpringBoot快速搭建web項(xiàng)目詳細(xì)步驟總結(jié) ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12

最新評(píng)論