Spring事務(wù)管理

說起事務(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

  1. 原子性(Atomicity)

要求事務(wù)所包含的全部操作是一個(gè)不可分割的整體莱衩,如果有一步發(fā)生異常爵嗅,則全部不提交。

  1. 一致性(Consistency)

A給B轉(zhuǎn)錢笨蚁,A減和B增這兩個(gè)操作必須保持一致操骡。

  1. 隔離性(Isolation)

事務(wù)會(huì)將一部分?jǐn)?shù)據(jù)與其他事務(wù)隔離,防止臟讀等赚窃。

  1. 持久性(Durability)

事務(wù)的結(jié)果被寫到持久化存儲(chǔ)器中。

事務(wù)四大隔離級(jí)別

隔離級(jí)別越高岔激,則性能相對(duì)越低勒极,反之亦然。

  1. Read Uncommitted

最低的隔離級(jí)別虑鼎,跟你直譯的意思一樣:可以讀取其它事務(wù)未完成的結(jié)果辱匿。(臟讀)

很明顯,臟讀 不可重復(fù)讀 和 幻讀這三個(gè)問題它都有炫彩。

  1. Read Committed

大部分?jǐn)?shù)據(jù)庫(kù)采用的默認(rèn)隔離級(jí)別匾七,比上一個(gè)隔離級(jí)別多了限定:在該事務(wù)完成后,才能讀取該事務(wù)的數(shù)據(jù)更新后的結(jié)果江兢。

它可以避免臟讀昨忆,但是也有不可重復(fù)讀取和幻讀的問題。

  1. Repeatable Read

可以保證在整個(gè)事務(wù)的過程中杉允,對(duì)同一筆數(shù)據(jù)的讀取結(jié)果是相同的邑贴,不管其他事務(wù)是否同時(shí)在對(duì)同一筆數(shù)據(jù)進(jìn)行更新席里,也不管其他事務(wù)對(duì)同一筆數(shù) 據(jù)的更新提交與否。

Repeatable Read隔離級(jí)別避免了臟讀和不可重復(fù)讀取的問題拢驾,但無法避免幻讀奖磁。

  1. 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. 代碼方式使用

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. 注解方式使用

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)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仗扬,隨后出現(xiàn)的幾起案子症概,更是在濱河造成了極大的恐慌,老刑警劉巖早芭,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彼城,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡退个,警方通過查閱死者的電腦和手機(jī)募壕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來语盈,“玉大人舱馅,你說我怎么就攤上這事〉痘模” “怎么了代嗤?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缠借。 經(jīng)常有香客問我干毅,道長(zhǎng),這世上最難降的妖魔是什么泼返? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任硝逢,我火速辦了婚禮,結(jié)果婚禮上符隙,老公的妹妹穿的比我還像新娘。我一直安慰自己垫毙,他們只是感情好霹疫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著综芥,像睡著了一般丽蝎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天屠阻,我揣著相機(jī)與錄音红省,去河邊找鬼。 笑死国觉,一個(gè)胖子當(dāng)著我的面吹牛吧恃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播麻诀,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼痕寓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蝇闭?” 一聲冷哼從身側(cè)響起呻率,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呻引,沒想到半個(gè)月后礼仗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逻悠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年元践,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹂风。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卢厂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惠啄,到底是詐尸還是另有隱情慎恒,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布撵渡,位于F島的核電站融柬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏趋距。R本人自食惡果不足惜粒氧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望节腐。 院中可真熱鬧外盯,春花似錦、人聲如沸翼雀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狼渊。三九已至箱熬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背城须。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工蚤认, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糕伐。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓砰琢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赤炒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氯析,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容