1.spring事務管理簡述
兩種事務管理方式:
- 編碼式事務管理:將事務控制代碼編寫在業務代碼之中。
-
聲明式事務管理:基于AOP(面向切面編程),事務管理與業務邏輯解耦。聲明式事務管理的兩種實現:
- 在配置文件(xml)中配置。
- 基于@Transactional注解。
2.SpringBoot中使用@Transactional注解
2.1.開啟事務注解
在項目主類上,加上注解@EnableTransactionManagement,例如:
1
2
3
4
5
6
|
@EnableTransactionManagement public class MySpringBootService extends WebMvcConfigurerAdapter { public static void main(String[] args) { SpringApplication.run(CoreService. class , args); } } |
2.2.在目標類、方法上添加注解@Transactional
1. 如果將@Transactional添加到類上,則表示此類的所有方法都開啟事務管理。如:
1
2
3
4
5
|
@Transactional (rollbackFor = Exception. class , propagation = Propagation.REQUIRED) @Service public class MyServiceImpl implements MyService { //class body } |
2. 如果將@Transactional添加到方法上,則表示此方法開啟事務管理。如:
1
2
3
4
5
|
@Transactional (rollbackFor = Exception. class , propagation = Propagation.REQUIRES_NEW) @Override public ActivityPo getActivityById(Long id){ //method body } |
3. 如果一個方法上存在@Transactional,且其所屬類上同樣存在@Transactional,則以方法級別的事務配置為準。
2.3.細化事務配置
關于@Transactional的可配置參數有很多,主要有propagation、rollbackFor等,可以適用于不同場景,這里不細說。
3.@Transactional事務實現機制
3.1.整體事務控制流程
- 當@Transactional注解的方法被類外部的代碼調用時,Spring在運行時為方法所在類生成一個AOP代理對象。
- 代理對象根據@Transactional的屬性,決定是否由事務攔截器TransactionInterceptor對此方法進行事務攔截。
- 在進行事務攔截時,會先開啟事務,然后執行業務代碼,根據執行是否出現異常,通過抽象事務管理器AbstractPlatformTransactionManager來進行rollback或者commit。
3.2.Spring AOP的兩種代理
- Spring AOP有兩種CglibAopProxy和JdkDynamicAopProxy,其中:
- CglibAopProxy在其內部類DynamicAdvisedInterceptor的intercept()方法中,判斷是否進行事務攔截。
- JdkDynamicAopProxy在其invoke()方法中,判斷是否進行事務攔截。
3.3.事務操作的底層實現
- 抽象事務管理器AbstractPlatformTransactionManager的rollback和commit都需要具體的實現類進行實現。
- 抽象事務管理器AbstractPlatformTransactionManager的父級接口是PlatformTransactionManager。
- 存在很多事務管理器實現類,例如DataSourceTransactionManager等。
- 不同的事務管理器管理不同的數據資源 DataSource,比如DataSourceTransactionManager管理者JDBC數據源。
- 應確保被調用方法中使用的數據源都加載了事務管理器。
4.@Transactional使用注釋實現及問題排查
4.1.數據庫引擎是否支持事務?
- MySql的引擎MyIsam不支持事務。
- 如需事務控制生效,則庫和表的引擎必須是InnoDB。
4.3.注解所在的類是否被加載成Bean?
- 章節3.1中第1條提到,需要在運行時為類生成代理對象。那么前提是這個類一定被Spring管理并加載成了一個Bean對象。
- 確保所在類是否被@Component、@Service、@Controller等等注解注釋。
4.2.注解所在方法是否為public修飾的?
- 章節3.2中,提到兩種AOP代理分別在intercept()和invoke()方法判斷是否進行事務攔截。
- 這兩個方法都會間接調用AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法來獲取事務控制的相關屬性。這其中有以下一段代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/** * Same signature as {@link #getTransactionAttribute}, but doesn't cache the result. * {@link #getTransactionAttribute} is effectively a caching decorator for this method. * <p>As of 4.1.8, this method can be overridden. * @since 4.1.8 * @see #getTransactionAttribute */ protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null ; } //... } |
- 這段代碼會導致no-public的方法無法進入事務控制。
- 所以,一定要確保自己需要進行事務控制的方法包含public修飾符。
4.5.是否發生了自調用問題?
- 章節3.1中第1條強調:只有當事務方法被當前類以外的代碼調用時,才會才由 Spring 生成的代理對象來管理。
- 上述邏輯會造成自調用問題:當事務方法被本類內部方法調用時,@Transactional并不生效。
- 自調用示例代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Service public class PersonServiceImpl implements PersonService{ @Resource private PersonDao personDao; public void insertPerson(Person person){ //自調用 personService.insert(person); //其他代碼 personDao.insertLog... } @Transactional (rollbackFor = Exception. class ) public void insert(Person person){ personDao.insert(person); } } |
- 上述代碼中,如果業務邏輯從非事務方法insertPerson()開始,在其中調用了事務方法insert(),則當insert()異常時,事務控制無效。
- 簡單說,就是在同一類中,非事務方法A調用了事務方法B,則當事務方法B異常,事務控制無效,A和B都不會回滾。
- 那么,在同一類中,事務方法A調用了非事務方法B,然后非事務方法B調用了事務方法C,事務是否生效?答案:是。因為事務方法A在被外部代碼調用時,已經開啟了事務管理。
4.6.所用數據源是否加載了事務管理器?
- 章節3.3中第5條提到:應確保被調用方法中使用的數據源都加載了事務管理器。
- 在SpringBoot項目中,如果是單數據源,那么系統會默認為單數據源配置事務管理器DataSourceTransactionManager。
- 在SpringBoot項目中,如果是多數據源,則一定確保所有的數據源都配置了事務管理器。
- 關于多數據源的配置方法可以參考: https://blog.csdn.net/hanchao5272/article/details/81209552
- 事務管理器的手動配置方法,可以參考如下:
1
2
3
4
5
|
@Bean @Primary public PlatformTransactionManager primaryTransactionManager( @Qualifier ( "sqlDataSource" ) DataSource sqlDataSource) { return new DataSourceTransactionManager(sqlDataSource); } |
4.4.觸發回滾的異常是否配置正確?
- 默認情況下,事務回歸針對的是uncheck的異常(運行時異常)或ERROR。
- 默認情況下,check的異常并不會觸發回滾,如FileNotFoundException。
- 如果想要簡單的配置成針對所有異常都回滾,可以這么做:
1
|
@Transactional (rollbackFor = Exception. class ) |
4.5.@Transactional的擴展配置propagation是否正確?
- 一般情況下,propagation屬性無需配置。其會使用默認配置,即:Propagation.REQUIRED。
-
有些propagation屬性會導致事務不會觸發,一定要注意:
- SUPPORTS: 如果存在事務,則進入事務;否則,以非事務方式運行。
- NOT_SUPPORTED: 如果存在事務,則掛起事務,并以非事務方式運行。
- NEVER: 以非事務形式運行,如果存在事務,則拋出異常。
4.7.事務管理的可選配置是否正確?
在SpringBoot中,關于事務的配置有兩個可選配置(一般無需配置):
- Springboot啟動類的@EnableTransactionManagement。
- Springboot配置文件的rollback-on-commit-failure屬性:
1
2
3
4
5
6
7
|
# yaml配置 spring: transaction: rollback-on-commit-failure: true # properties配置 spring.transaction.rollback-on-commit-failure=true |
請確保上述配置都是正確的(或者未配置)。
到此這篇關于詳解在SpringBoot中@Transactional事物操作和事物無效問題排查的文章就介紹到這了,更多相關SpringBoot使用@Transactional內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/hanchao5272/article/details/90343882