最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決@Transaction注解導致動態(tài)切換更改數據庫失效問題

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

@Transaction注解導致動態(tài)切換更改數據庫失效

使用場景

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

遇到問題

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

解決

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

@Transactional失效的場景及原理

1.@Transactional修飾的方法

為非public方法,這個時候@Transactional會實現(xiàn)。

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

2.在類內部沒有添加@Transactional的方法

調用了@Transactional方法時,當你調用是,他也不會回滾

測試代碼如下

@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");
        //插入到數據庫
        userMapper.insertSelective(userEntity);
        //手動拋出異常
        throw new IndexOutOfBoundsException();
    }
    @Override
    public void saveOne() {
        insertOne();
    }
}

失敗的原理:@Transactional是基于動態(tài)代理對象來實現(xiàn)的,而在類內部的方法的調用是通過this關鍵字來實現(xiàn)的,沒有經過動態(tài)代理對象,所以事務回滾失效。

3.就是在@Transactional方法內部捕獲了異常

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

代碼如下:

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

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

代碼如下:

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

失敗原理:這時候我們來看看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) {
              //異常時,在catch邏輯中回滾事務
                this.completeTransactionAfterThrowing(txInfo, var17);
                throw var17;
            } finally {
                this.cleanupTransactionInfo(txInfo);
            }
            this.commitTransactionAfterReturning(txInfo);
            return result;
        }
    }

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

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 解決maven沒有打包xml文件的問題

    解決maven沒有打包xml文件的問題

    這篇文章主要介紹了解決maven沒有打包xml文件的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java兩個線程同時寫一個文件

    java兩個線程同時寫一個文件

    這篇文章主要為大家詳細介紹了java兩個線程同時寫一個文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • SpringBoot實現(xiàn)跨域的幾種常用方式總結

    SpringBoot實現(xiàn)跨域的幾種常用方式總結

    跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,或者涉及到兩個不同域名的資源之間的交互,由于同源策略(Same Origin Policy)的限制,瀏覽器不允許跨域請求,本文小編給大家分享了SpringBoot實現(xiàn)跨域的幾種常用方式,需要的朋友可以參考下
    2023-09-09
  • SpringCloudConfig之client端報錯Could?not?resolve?placeholder問題

    SpringCloudConfig之client端報錯Could?not?resolve?placeholder問

    這篇文章主要介紹了SpringCloudConfig之client端報錯Could?not?resolve?placeholder?‘from‘?in?value?“${from}“問題及解決方案,具有很好的參考價值,希望對大家有所幫助
    2022-12-12
  • SpringBoot如何實現(xiàn)定時任務示例詳解

    SpringBoot如何實現(xiàn)定時任務示例詳解

    使用定時任務完成一些業(yè)務邏輯,比如天氣接口的數據獲取,定時發(fā)送短信,郵件。以及商城中每天用戶的限額,定時自動收貨等等,這篇文章主要給大家介紹了關于SpringBoot如何實現(xiàn)定時任務的相關資料,需要的朋友可以參考下
    2021-10-10
  • Spring單元測試控制Bean注入的方式

    Spring單元測試控制Bean注入的方式

    這篇文章主要介紹了Spring單元測試控制Bean注入的方式,其中續(xù)注意的是在Bean上加@Order(xxx)是無法控制bean注入的順序的,需要的可以參考一下
    2023-04-04
  • JAVA實現(xiàn)讀取txt文件內容的方法

    JAVA實現(xiàn)讀取txt文件內容的方法

    本篇文章主要介紹了JAVA實現(xiàn)讀取txt文件內容的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Idea配置maven-tomcat-plugin插件實現(xiàn)項目部署

    Idea配置maven-tomcat-plugin插件實現(xiàn)項目部署

    今天小編就為大家分享一篇關于Idea配置maven-tomcat-plugin插件實現(xiàn)項目部署,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • SpringBoot利用注解來實現(xiàn)Redis分布式鎖

    SpringBoot利用注解來實現(xiàn)Redis分布式鎖

    有些業(yè)務請求,屬于耗時操作,需要加鎖,防止后續(xù)的并發(fā)操作,同時對數據庫的數據進行操作,需要避免對之前的業(yè)務造成影響。本文將利用注解來實現(xiàn)Redis分布式鎖,需要的可以參考一下
    2022-09-09
  • java HttpClient傳輸json格式的參數實例講解

    java HttpClient傳輸json格式的參數實例講解

    這篇文章主要介紹了java HttpClient傳輸json格式的參數實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01

最新評論

厦门市| 惠州市| 饶河县| 赫章县| 镇江市| 柳江县| 璧山县| 九龙县| 眉山市| 称多县| 阜平县| 凤山市| 宁强县| 志丹县| 铜陵市| 中宁县| 信阳市| 寿阳县| 孝昌县| 佳木斯市| 长乐市| 富裕县| 尉犁县| 金坛市| 庆城县| 喀喇沁旗| 噶尔县| 古田县| 兴宁市| 久治县| 祁东县| 黄龙县| 天峻县| 顺义区| 嘉荫县| 扶沟县| 昭平县| 平塘县| 疏附县| 鲁甸县| 清徐县|