SpringBoot注解@Transactional詳解以及事務(wù)失效
一、事務(wù)的特點(diǎn)ACID
- 原子性(Atomicity):事務(wù)最小的執(zhí)行單位,不允許分割,事務(wù)的原子性確保動作要么全部完成,要么完全失敗。
- 一致性(Consistency):執(zhí)行事務(wù)前后,數(shù)據(jù)保持一致,例如在上面的轉(zhuǎn)賬例子中,無論事務(wù)是否成功,轉(zhuǎn)賬者和收款人的總額應(yīng)該是不變的。
- 隔離性(Isolation):并發(fā)訪問數(shù)據(jù)庫時,一個用戶的事務(wù)不被其它事務(wù)干擾,各并發(fā)事務(wù)之間的數(shù)據(jù)庫是獨(dú)立的。
- 持久性(Durability):一個事務(wù)被提交后,它對數(shù)據(jù)庫中數(shù)據(jù)的改變是持久的,即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對其有任何影響。
二、Spring對事務(wù)的支持
程序是否支持事務(wù)的先決條件是數(shù)據(jù)庫,比如使用MySQL的話,如果選擇的是innodb,那么支持事務(wù),如果選擇的是myisam,那么從根上就不支持事務(wù)了
MySQL怎么保證原子性?
如果要保證原子性,就需要在發(fā)生異常時,對已經(jīng)執(zhí)行的操作進(jìn)行回滾,在MySQL中,恢復(fù)機(jī)制是通過回滾日志實(shí)現(xiàn)的,所有事務(wù)進(jìn)行的修改,都會先記錄到這個回滾日志中,然后再執(zhí)行相關(guān)的操作。
如果在執(zhí)行過程中遇到異常,我們直接利用回滾日志中的信息將數(shù)據(jù)回滾到修改之前的樣子即可,并且回滾日志會先將數(shù)據(jù)持久化到磁盤上,這樣就可以保證即便在遇到數(shù)據(jù)庫突然宕機(jī),當(dāng)用戶再次重啟數(shù)據(jù)庫時,數(shù)據(jù)庫還是能夠通過查回滾日志來回滾之前未完成的事務(wù)。
三、Spring支持兩種事務(wù)管理
3.1編程事務(wù)管理
通過TransactionTemplate或者TransactionManager手動管理事務(wù),在實(shí)際應(yīng)用中卻很少使用,下面通過代碼來演示,使用TransactionTemplate進(jìn)行編程式事務(wù)管理
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransactionTemplate() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(final TransactionStatus transactionStatus) {
try {
//TODO 業(yè)務(wù)代碼
} catch (final Exception e) {
// 異常時回滾
transactionStatus.setRollbackOnly();
}
}
});
}
使用TransactionManager進(jìn)行編程式事務(wù)管理
@Resource
private PlatformTransactionManager transactionManager;
public void testTransactionManager() {
final TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
//TODO 業(yè)務(wù)代碼
transactionManager.commit(status);
} catch (final Exception e) {
// 異常時回滾
transactionManager.rollback(status);
}
}
3.2聲明式事務(wù)管理
聲明式事務(wù)管理,實(shí)際上是通過AOP實(shí)現(xiàn),基于@Transactional的注解使用最多
@Transactional
public void testTransactional() {
userInfoDao.save(userInfo);
userInfoDetailDao.save(userInfoDetail);
}
在實(shí)際的業(yè)務(wù)開發(fā)中,大家一般使用@Transactional注解來開啟事務(wù),但很多人并不是很清楚這個注解中的參數(shù)是什么意思?有什么用?
3.2.1@Transactional的作用范圍
- 方法:推薦將注解用于方法上,不過需要注意的是:該注解只能應(yīng)用到 public 方法上,否則不生效。
- 類:如果將注解用在類上,表明該類中所有的 public 方法都生效。
- 接口:不推薦在接口上使用。
@Transactional注解源碼如下,里面包含了基本事務(wù)屬性的配置:
package org.springframework.transaction.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
@Transactional 的常用參數(shù)介紹
屬性名 | 說明 |
propagation | 事務(wù)的傳播行為,默認(rèn)值為 REQUIRED |
isolation | 事務(wù)的隔離級別,默認(rèn)值采用 DEFAULT |
timeout | 事務(wù)的超時時間,默認(rèn)值為-1(不會超時),如果超過該時間限制但事務(wù)還沒有完成,則自動回滾事務(wù) |
readOnly | 指定事務(wù)是否為只讀事務(wù),默認(rèn)值為 false |
rollbackFor | 用于指定能夠觸發(fā)事務(wù)回滾的異常類型,并且可以指定多個異常類型 |
關(guān)于傳播行為propagation屬性:
- REQUIRED:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個事務(wù)。這是最常見的選擇。
- SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
- MANDATORY:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
- REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
- NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
- NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
- NESTED:支持當(dāng)前事務(wù),如果當(dāng)前事務(wù)存在,則執(zhí)行一個嵌套事務(wù),如果當(dāng)前沒有事務(wù),就新建一個事務(wù)。
3.2.2@Transactional失效場景
- 非 public 修飾的方法;
- timeout 超時時間設(shè)置過??;
- 代碼中使用 try/catch 處理異常;
- 調(diào)用類內(nèi)部的@Transactional 方法;
- 數(shù)據(jù)庫不支持事務(wù)。