成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇讓你學會 11個Spring 失效場景

開發 架構
在開發中,我們都是通過@Controller,@Service,@Component,@Repository等注解自動的實現依賴注入實例化的功能,但假如說在相應的控制層,業務層,數據層忘記加相應的注解,那么也是會失效的。

其實關于spring事務失效的場景,網絡上文章介紹的不少,參差不齊。這里只分享下自己的見解,時長大概10分鐘左右,先上個圖介紹下。

1.訪問權限問題

事務方法需要定義public,非public方法事務會失效。事務攔截器TransactionalInterceptor會在執行方法前進行攔截,通過動態代理方式如果是cglib就是intercept方法或者jdk的invoke方法間接調用AbstractFallbackTransactionAttributeSource類的getTransactionAttribute方法獲取配置信息,附上源碼圖:

進一步的跟蹤getTransactionAttribute方法,我們就能看到,spring對于非public修飾的方式,返回的事務對象是null,其中allowPublicMethodsOnly返回的是一個布爾false。

2.方法被final修飾

事務底層使用了aop,那么也就是說通過jdk或者是cglib生成代理類,在代理類中實現的事務的功能,如果說方法是final修飾的了,那么就會導致代理類中無法重寫該方法,從而導致添加事務失敗。同樣的如果是static的修飾的話也是無法通過動態代理變成事務方法。

3.方法內部調用

簡單來說就是一個方法內部調用另一個方法,但是另一個方式是有事務的,這樣也會導致事務失效,因為這個調用的是this對象的方法,而不是另一個方法持有的對象,可以這里理解。

如果想要在方法內部調用另一個方法也有事務的話,就需要新建一個service對象持有。

@Service
public class TmTrimServicebackImpl{
public void getById(Long id) {
TmTrimServiceliImpl.getTrimById(id);
}
}
@Service
public class TmTrimServiceliImpl{
@Transactional(rollbackFor=Exception.class)
public void getTrimById(Long id) {
TmTrimVO tmTrimVO = new TmTrimVO();
}
}

這樣,通過新建一個service方法,將事務添加到新建的service方法里就可以了。說到這里可能小伙伴覺得這樣有點麻煩,那么是否有沒有其他的方式不新建一個方法呢,答案是可以的,就是注入自己,利用了spring ioc內部的三級緩存的機制,這里注入自己就很好的保證了也不會出現循環依賴:

@Service
public class TmTrimServicebackImpl{
@Autowired
private TmTrimServicebackImpl tmTrimServicebackImpl;
public void getById(Long id) {
tmTrimServicebackImpl.getTrimById(id);
}
@Transactional(rollbackFor=Exception.class)
public void getTrimById(Long id) {
TmTrimVO tmTrimVO = new TmTrimVO();
}
}

其實到了這一步,還是發現有點不太雅觀,并不是說上面代碼有什么問題只是覺得,可以讓上面代碼更加好看一點,那么有沒有呢,答案是有的,是什么呢?這就不得不佩服spring強大完善的支持,那就是AopContext.currentProxy(),這個就是創建代理類,在方法調·調用前后切入,這個代理類對象是保存在ThreadLocal中的,所以通過這個代理類對象調用事務方法就能生效了。

@Service
public class TmTrimServicebackImpl{
public void getById(Long id) {
((TmTrimServicebackImpl)AopContext.currentProxy()).getTrimById(id);
}
@Transactional(rollbackFor=Exception.class)
public void getTrimById(Long id) {
TmTrimVO tmTrimVO = new TmTrimVO();
}
}

這樣看來,代碼是不是就優雅多了,哈哈!!!

4.未被spring事務管理

這里需要明確一個前提,就是使用spring事務的前提,就是對象要被spring管理就需要創建bean實例,在開發中,我們都是通過@Controller,@Service,@Component,@Repository等注解自動的實現依賴注入實例化的功能,但假如說在相應的控制層,業務層,數據層忘記加相應的注解,那么也是會失效的。因為沒有交給spring管理,例如:

5.多線程調用

回想起前幾年配置事務管理器時,都會有這樣的一段配置:

通過這一段配置也可以知道,其實spring事務就是通過數據庫連接事務多線程連接會導致持有的connetion不是同一個,從網上找了一張圖,通過這張圖進一步理解:

接著附上偽代碼結合上面的圖進一步理解:

@Slf4j
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleService roleService;
@Transactional
public void add(UserModel userModel) throws Exception {
userMapper.insertUser(userModel);
new Thread(() -> {
roleService.doOtherThing();
}).start();
}
}
@Service
public class RoleService {
@Transactional
public void doOtherThing() {
System.out.println("保存role表數據");
}
}

事務add方法中調用了另一個事務doOtherThing,但是事務方法是在另一個線程中調用的,這樣就會導致兩個方法不在同一個線程中,獲取到的數據庫鏈接不一樣,是兩個不同的事務,一旦doOtherThing發生異常,add方法也是不可能發生回滾的.這里需要解釋以下什么是同一個事務,也就是說只有擁有同一個數據庫連接才能同時提交和回滾。如果在不同的線程,拿到的數據庫連接肯定是不一樣的,所以是不同的事務。

6.多線程調用

這個就沒什么好講的了,也就是innodb和myisam引擎的不同,5版本以前默認是myisam引擎,這個引擎是不支持事務的,5版本以后的innodb是支持事務的。

7.未開啟事務

這個其實可能也是比較容易忽略的,因為我們印象里好像沒怎么配置過怎么開啟事務,也確實是這樣哈,為什么?其實原因很簡單,springboot項目通過DataSourceTransactionManagerAutoConfiguration這個類已經默默的為我們開啟了事務。

這個類會加載spring.datasource這個配置文件從而啟動事務,如果是非springboot項目就需要自己手動在xml文件中配置事務管理器。

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"> 
<property name="dataSource" ref="dataSource"></property>
</bean>

類似這樣的從而開啟事務。

8.錯誤的傳播特性

在使用@Transactional注解時,是可以指定propagation參數的,該參數是用來指定事務的傳播特性,其中只有required,requires_new,nested這三種才會創建新事務:

@Service
public class UserService {
@Transactional(propagation = Propagation.NEVER)
public void add(UserModel userModel) {
saveData(userModel);
updateData(userModel);
}
}

像上面的Propagation.NEVER這種類型的傳播特性不支持事務,如果有事務則會拋異常。

9.自己吞了異常

@Slf4j
@Service
public class UserService {
@Transactional
public void add(UserModel userModel) {
try {
saveData(userModel);
updateData(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

像這種手動try...catch了異常,又沒有手動拋出,那么sring就會認為程序是異常的就不會回滾了。

10.手動拋了別的異常

Slf4j
@Service
public class UserService {
@Transactional
public void add(UserModel userModel) throws Exception {
try {
saveData(userModel);
updateData(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new Exception(e);
}
}
}

捕獲了異常又拋出了exception異常,事務同樣不會回滾,因為spring事務默認情況下只會回滾RuntimeException(運行時異常)和Error(錯誤),對于普通的Exception(非運行時異常),不會回滾,網上找了一張圖:

這里exception里除了分為運行時異常和非運行時異常(ioException)。

1) 讓checked例外也回滾:

在整個方法前加上 @Transactional(rollbackFor=Exception.class)

2)  讓unchecked例外不回滾:

@Transactional(notRollbackFor=RunTimeException.class)

3)不需要事務管理的(只查詢的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)

這里需要提及的一句是,如果是自定義了的異常,比如說我自定義了DALException異常,那么就應該是@Transactional(notRollbackFor=DALException.class),一旦拋出的異常不屬于DALException異常,那么事務也是不會生效的。

11.嵌套事務回滾多了

其實這個就有點像是js里的冒泡事件,可能我只是需要底部,結果外層窗口事件也觸發了,聯想到事務這里,那么也是一樣的,嵌套多個可能只是想回滾對應的事務,就不用把其他事務也回滾了,這個可以通過try...catch來處理,將需要處理回滾的事務放這里面就不會把外層的也會滾了。

本文轉載自微信公眾號「小王子古木屋」,可以通過以下二維碼關注。轉載本文請聯系小王子古木屋公眾號。

責任編輯:武曉燕 來源: 小王子古木屋
相關推薦

2021-09-14 07:26:26

組合問題循環

2021-08-26 13:22:46

雪花算法隨機數

2022-02-11 08:45:28

通信協議CAN

2022-08-29 08:00:11

哈希表數組存儲桶

2023-01-03 08:31:54

Spring讀取器配置

2022-01-02 08:43:46

Python

2024-04-12 09:01:08

2022-06-04 07:46:41

HeapJVM

2022-02-07 11:01:23

ZooKeeper

2021-07-02 09:45:29

MySQL InnoDB數據

2021-07-06 08:59:18

抽象工廠模式

2021-07-05 22:11:38

MySQL體系架構

2022-08-23 08:00:59

磁盤性能網絡

2021-05-11 08:54:59

建造者模式設計

2022-08-26 09:29:01

Kubernetes策略Master

2023-11-28 08:29:31

Rust內存布局

2020-09-23 10:59:00

開發技能代碼

2021-09-28 08:59:30

復原IP地址

2021-10-14 10:22:19

逃逸JVM性能

2022-04-12 08:30:52

回調函數代碼調試
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: a天堂在线| 中文字幕亚洲视频 | 国产免费一区二区 | 国产三级精品视频 | 91精品国产综合久久精品图片 | 亚洲精品二区 | 日韩午夜一区二区三区 | 欧美久久天堂 | 日本成人在线免费视频 | 一区二区三区中文字幕 | 污书屋| 精品一区二区三区91 | 国产91久久久久 | 欧洲一区二区视频 | 久久综合爱 | 欧美日韩国产一区二区三区 | 中文字幕一区二区三区四区五区 | 国产不卡在线观看 | 中文字幕在线网 | 欧美在线视频网站 | 性做久久久久久免费观看欧美 | 午夜久久久久久久久久一区二区 | 男女午夜免费视频 | 成人在线电影网站 | 拍真实国产伦偷精品 | 六月婷婷久久 | 美女在线视频一区二区三区 | 久久久xx| 日本精品久久久久久久 | 婷婷在线视频 | 四虎影院新地址 | 久久精品视频亚洲 | 九九热这里 | 亚洲国产aⅴ成人精品无吗 亚洲精品久久久一区二区三区 | 亚洲国产成人av好男人在线观看 | 91新视频 | 亚洲午夜视频 | h在线免费观看 | 国产精品久久久久不卡 | 国产成人综合一区二区三区 | www国产成人免费观看视频,深夜成人网 |