說起事務(wù),大家應(yīng)該多多少少用過涛碑,尤其是在一個(gè)service方法中調(diào)用多次dao操作蚪腋,我們一定要用到事務(wù)(@Transational注解),那么這個(gè)事務(wù)的默認(rèn)隔離級(jí)別和傳播機(jī)制是什么呢?
先來講講臟讀 不可重復(fù)讀 和 幻讀惰帽。
臟讀:我們?cè)诓l(fā)編程中是很熟悉的,通俗的講就是你讀得數(shù)據(jù)已經(jīng)被修改了父虑,已經(jīng)過時(shí)失去意義了该酗。
不可重復(fù)讀: 同一個(gè)事務(wù)里面多次讀取同一行數(shù)據(jù),卻返回不同的結(jié)果士嚎。
幻讀:同樣一筆查詢?cè)谡麄€(gè)事務(wù)過程中多次執(zhí)行后呜魄,查詢所得的結(jié)果集不一樣。
事務(wù)四大特性 ACID
- 原子性
(Atomicity)
要求事務(wù)所包含的全部操作是一個(gè)不可分割的整體莱衩,如果有一步發(fā)生異常爵嗅,則全部不提交。
- 一致性
(Consistency)
A給B轉(zhuǎn)錢笨蚁,A減和B增這兩個(gè)操作必須保持一致操骡。
- 隔離性
(Isolation)
事務(wù)會(huì)將一部分?jǐn)?shù)據(jù)與其他事務(wù)隔離,防止臟讀等赚窃。
- 持久性
(Durability)
事務(wù)的結(jié)果被寫到持久化存儲(chǔ)器中。
事務(wù)四大隔離級(jí)別
隔離級(jí)別越高岔激,則性能相對(duì)越低勒极,反之亦然。
- Read Uncommitted
最低的隔離級(jí)別虑鼎,跟你直譯的意思一樣:可以讀取其它事務(wù)未完成的結(jié)果辱匿。(臟讀)
很明顯,臟讀 不可重復(fù)讀 和 幻讀這三個(gè)問題它都有炫彩。
- Read Committed
大部分?jǐn)?shù)據(jù)庫(kù)采用的默認(rèn)隔離級(jí)別匾七,比上一個(gè)隔離級(jí)別多了限定:在該事務(wù)完成后,才能讀取該事務(wù)的數(shù)據(jù)更新后的結(jié)果江兢。
它可以避免臟讀昨忆,但是也有不可重復(fù)讀取和幻讀的問題。
- Repeatable Read
可以保證在整個(gè)事務(wù)的過程中杉允,對(duì)同一筆數(shù)據(jù)的讀取結(jié)果是相同的邑贴,不管其他事務(wù)是否同時(shí)在對(duì)同一筆數(shù)據(jù)進(jìn)行更新席里,也不管其他事務(wù)對(duì)同一筆數(shù) 據(jù)的更新提交與否。
Repeatable Read隔離級(jí)別避免了臟讀和不可重復(fù)讀取的問題拢驾,但無法避免幻讀奖磁。
- Serializable
最為嚴(yán)格的隔離級(jí)別,所有的事務(wù)操作都必須依次順序執(zhí)行繁疤,可以避免其他隔離級(jí)別遇到的所有問題咖为,是最為安全的隔離級(jí)別, 但同時(shí)也是性能最差的隔離級(jí)別稠腊。
通常情況下躁染,我們會(huì)使用其他隔離級(jí)別加上相應(yīng)的并發(fā)鎖的機(jī)制來控制對(duì)數(shù)據(jù)的訪問,這樣既保證 了系統(tǒng)性能不會(huì)損失太大麻养,也能夠一定程度上保證數(shù)據(jù)的一致性褐啡。
Spring事務(wù)傳播機(jī)制
從JDBC的事務(wù)說起
我們都知道,JDBC給我們提供了事務(wù)鳖昌。
1
2
3
4
5
6
7
try{
con.setAutoCommit(false);//開啟事務(wù)
......
con.commit();//try的最后提交事務(wù)
} catch() {
con.rollback();//回滾事務(wù)
}
獲取事務(wù)隔離級(jí)別
1
Connection.getTransactionIsolation()
設(shè)置事務(wù)隔離級(jí)別
1
con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
Spring事務(wù)機(jī)制
Spring并不會(huì)直接管理事務(wù)备畦,而是提供了事務(wù)管理器,將事務(wù)管理的職責(zé)委托給JPA JDBC JTA DataSourceTransaction JMSTransactionManager 等框架提供的事務(wù)來實(shí)現(xiàn)许昨。
那么懂盐,Spring提供的事務(wù)管理器是什么呢?
是PlatformTransactionManager.java接口:
PlatformTransactionManager.java
Spring提供的事務(wù)管理器。不同的事務(wù)遵循該事務(wù)管理器的API糕档,便能很輕松的交給Spring管理莉恼。
1
2
3
4
5
6
7
8
public interface PlatformTransactionManager {
// 通過Transation定義 獲取Transation
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
// 提交事務(wù)
void commit(TransactionStatus var1) throws TransactionException;
// 回滾事務(wù)
void rollback(TransactionStatus var1) throws TransactionException;
}
可以看到它里面引用到了TransactionDefinition和TransactionStatus.
TransactionDefinition.java
它里面包含了事務(wù)的定義。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public interface TransactionDefinition {
// 傳播機(jī)制
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
// 隔離級(jí)別
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();
// 獲取隔離級(jí)別
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
@Nullable
String getName();
}
TransactionStatus.java
事務(wù)的狀態(tài)速那。
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
Spring默認(rèn)事務(wù)使用
- 代碼方式使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Autowired
private PlatformTransactionManager transactionManager;
public void testTX(){
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(definition);
try {
// 業(yè)務(wù)邏輯
// ...
// 提交事務(wù)
transactionManager.commit(status);
}catch (Exception e){
// 發(fā)生異常俐银,事務(wù)回滾
transactionManager.rollback(status);
}
}
- 注解方式使用
1
2
3
4
@Transactional
void testTX2(){
// 業(yè)務(wù)邏輯 ...
}
這不是玄學(xué),它的底層是依靠AOP動(dòng)態(tài)代理實(shí)現(xiàn)端仰,其實(shí)重新渲染出的代碼和第一個(gè)使用方式類似捶惜,不過大大減少了開發(fā)復(fù)雜度。
擴(kuò)展:@Transactional注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
//指定使用的事務(wù)管理器
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
// 可選的事務(wù)傳播行為設(shè)置
Propagation propagation() default Propagation.REQUIRED;
// 可選的事務(wù)隔離級(jí)別設(shè)置
Isolation isolation() default Isolation.DEFAULT;
// 事務(wù)超時(shí)時(shí)間設(shè)置
int timeout() default -1;
// 讀寫或只讀事務(wù)荔烧,默認(rèn)讀寫
boolean readOnly() default false;
// 導(dǎo)致事務(wù)回滾的異常類數(shù)組
Class<? extends Throwable>[] rollbackFor() default {};
// 導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組
String[] rollbackForClassName() default {};
// 不會(huì)導(dǎo)致事務(wù)回滾的異常類數(shù)組
Class<? extends Throwable>[] noRollbackFor() default {};
// 不會(huì)導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組
String[] noRollbackForClassName() default {};
}
Spring事務(wù)實(shí)踐
非入門選手下面的demo可能會(huì)引起你的不適(浪費(fèi)時(shí)間)吱七。
假設(shè)我要完成一個(gè)功能,當(dāng)刪除用戶的時(shí)候鹤竭,將與該用戶有關(guān)的所有數(shù)據(jù)行都刪除踊餐。
1
2
3
4
5
6
public void delUser(Integer userId) {
// 刪除和用戶相關(guān)的信息
otherRepository.deleteByUserId(userId);
// 刪除用戶
userRepository.deleteById(userId);
}
這樣的寫法一般來講,會(huì)成功的完成任務(wù)臀稚。但是如果這樣一段代碼:
1
2
3
4
5
6
7
8
9
public void delUser(Integer userId) {
// 刪除和用戶相關(guān)的信息
otherRepository.deleteByUserId();
if (true) {
throw new RuntimeException("xxx");
}
// 刪除用戶
userRepository.deleteById(userId);
}
結(jié)果會(huì)是:deleteByUserId()執(zhí)行成功吝岭,deleteById()執(zhí)行失敗,不滿足數(shù)據(jù)的一致性。
所以我們需要事務(wù)來限制:要么全部執(zhí)行苍碟,要么全部不執(zhí)行(方法中有異常就自動(dòng)回滾)酒觅。那怎么實(shí)現(xiàn)呢,只需要在方法上加一個(gè)注解:@Transactional
1
2
3
4
5
6
7
8
9
10
@Transactional
public void delUser(Integer userId) {
// 刪除和用戶相關(guān)的信息
otherRepository.deleteByUserId();
if (true) {
throw new RuntimeException("xxx");
}
// 刪除用戶
userRepository.deleteById(userId);
}
Spring 加載第三方事務(wù)管理
比如我有個(gè)需求(接著上次的強(qiáng)票系統(tǒng)II)微峰,要求信息不能丟失舷丹,要用到RabbitMQ的事務(wù)管理,那怎么去加載到Spring的事務(wù)管理器中呢蜓肆?
1
2
3
4
5
6
7
8
9
10
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
return connectionFactory;
}
@Bean
public RabbitTransactionManager rabbitTransactionManager(ConnectionFactory connectionFactory) {
return new RabbitTransactionManager(connectionFactory);
}
我們只需要這樣做便可以使的使用@Transactional注解來實(shí)現(xiàn)對(duì)RabbitMQ的事務(wù)管理,其它框架也類似颜凯。
Spring(72)spring事務(wù)(6)