唐山網(wǎng)站建設(shè)拓seo知識(shí)總結(jié)
前言
🌟🌟本期講解關(guān)于spring 事務(wù)傳播機(jī)制介紹~~~
🌈感興趣的小伙伴看一看小編主頁(yè):GGBondlctrl-CSDN博客
🔥 你的點(diǎn)贊就是小編不斷更新的最大動(dòng)力 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
🎆那么廢話不多說(shuō)直接開(kāi)整吧~~
目錄
📚?1.事務(wù)的隔離級(jí)別
🚀1.1MySQL事務(wù)隔離級(jí)別
🚀1.2Spring事務(wù)隔離級(jí)別
📚?2.Spring事務(wù)傳播機(jī)制
🚀2.1什么是事務(wù)的傳播機(jī)制
🚀2.2事務(wù)隔離與傳播的區(qū)別
🚀2.3事務(wù)的傳播機(jī)制
🚀2.4事務(wù)傳播機(jī)制代碼演示
2.4.1REQUIRED
?2.4.2REQUIRES_NEW
2.4.3NEVER
2.4.4NESTED
🚀2.5NESTED和REQUIRED 區(qū)別
📚?3.總結(jié)
📚?1.事務(wù)的隔離級(jí)別
🚀1.1MySQL事務(wù)隔離級(jí)別
讀未提交(READ UNCOMMITTED): 讀未提交, 也叫未提交讀. 該隔離級(jí)別的事務(wù)可以看到其他事務(wù)中未提交的數(shù)據(jù).
因?yàn)槠渌聞?wù)未提交的數(shù)據(jù)可能會(huì)發(fā)?回滾, 但是該隔離級(jí)別卻可以讀到, 我們把該級(jí)別讀到的數(shù)據(jù)稱之為臟數(shù)據(jù), 這個(gè)問(wèn)題稱之為臟讀.(就是一個(gè)事務(wù)還沒(méi)有寫完,另一個(gè)事務(wù)就在讀了)
讀提交(READ COMMITTED): 讀已提交, 也叫提交讀. 該隔離級(jí)別的事務(wù)能讀取到已經(jīng)提交事務(wù)的數(shù)據(jù)
該隔離級(jí)別不會(huì)有臟讀的問(wèn)題.但由于在事務(wù)的執(zhí)?中可以讀取到其他事務(wù)提交的結(jié)果, 所以在不同時(shí)間的相同 SQL 查詢可能會(huì)得到不同的結(jié)果, 這種現(xiàn)象叫做不可重復(fù)讀
(大致就是,事務(wù)A在寫完后,B讀了之后,A又再次修改了,那么B再次讀之后,就會(huì)發(fā)現(xiàn)兩次的結(jié)果不一樣)
可重復(fù)讀(REPEATABLE READ): 事務(wù)不會(huì)讀到其他事務(wù)對(duì)已有數(shù)據(jù)的修改, 即使其他事務(wù)已提交. 也就可以確保同?事務(wù)多次查詢的結(jié)果?致, 但是其他事務(wù)新插?的數(shù)據(jù), 是可以感知到的. 這也就引發(fā)了幻讀問(wèn)題. 可重復(fù)讀, 是 MySQL 的默認(rèn)事務(wù)隔離級(jí)別.
?如此級(jí)別的事務(wù)正在執(zhí)?時(shí), 另?個(gè)事務(wù)成功的插?了某條數(shù)據(jù), 但因?yàn)樗看尾樵兊慕Y(jié)果都是?樣的, 所以會(huì)導(dǎo)致查詢不到這條數(shù)據(jù), ??重復(fù)插?時(shí)?失敗(因?yàn)槲?約束的原因). 明明在事務(wù)中查詢不到這條信息,但??就是插?不進(jìn)去, 這個(gè)現(xiàn)象叫幻讀
串?化(SERIALIZABLE): 序列化, 事務(wù)最?隔離級(jí)別. 它會(huì)強(qiáng)制事務(wù)排序, 使之不會(huì)發(fā)?沖突, 從?解決了臟讀, 不可重復(fù)讀和幻讀問(wèn)題, 但因?yàn)閳?zhí)?效率低, 所以真正使?的場(chǎng)景并不多?
🚀1.2Spring事務(wù)隔離級(jí)別
Spring 中事務(wù)隔離級(jí)別有5 種:
1. Isolation.DEFAULT : 以連接的數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別為主.
2. Isolation.READ_UNCOMMITTED : 讀未提交, 對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 READ UNCOMMITTED
3. Isolation.READ_COMMITTED : 讀已提交,對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 READ COMMITTED
4. Isolation.REPEATABLE_READ : 可重復(fù)讀, 對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 REPEATABLE READ
5. Isolation.SERIALIZABLE : 串?化, 對(duì)應(yīng)SQL標(biāo)準(zhǔn)中 SERIALIZABLE
設(shè)置事務(wù)的隔離級(jí)別代碼如下:
@Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT)//設(shè)置所有回滾異常類型@RequestMapping("/r7")public Boolean r7(String userName, String password) throws IOException {Integer result = userService.registUser(userName, password);System.out.println("插入用戶表, result: "+ result);if (true){throw new IOException();}return true;}
解釋:
在代碼中,注解里的參數(shù)rollbackfor指定所有異常都需要進(jìn)行回滾,然后isolation指定是與數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別是一致的,那么這里的spring事務(wù)的隔離級(jí)別就是可重復(fù)讀;
📚?2.Spring事務(wù)傳播機(jī)制
🚀2.1什么是事務(wù)的傳播機(jī)制
事務(wù)傳播機(jī)制就是: 多個(gè)事務(wù)?法存在調(diào)?關(guān)系時(shí), 事務(wù)是如何在這些?法間進(jìn)?傳播的
就比如,兩個(gè)方法,都被transaction修飾了,假如這里的兩個(gè)方法存在調(diào)用的關(guān)系,那么這里的事務(wù)是如何進(jìn)行傳播的,是使用A的事務(wù),還是使用B的事務(wù)呢?
🚀2.2事務(wù)隔離與傳播的區(qū)別
事務(wù)隔離級(jí)別解決的是多個(gè)事務(wù)同時(shí)調(diào)??個(gè)數(shù)據(jù)庫(kù)的問(wèn)題
如下圖:
?事務(wù)傳播機(jī)制解決的是?個(gè)事務(wù)在多個(gè)節(jié)點(diǎn)(?法)中傳遞的問(wèn)題
🚀2.3事務(wù)的傳播機(jī)制
@Transactional 注解?持事務(wù)傳播機(jī)制的設(shè)置, 通過(guò) propagation 屬性來(lái)指定傳播?為.
Spring 事務(wù)傳播機(jī)制有以下 7 種:
B是被調(diào)用的一方(service),A是調(diào)用的一方(controller)
1. Propagation.REQUIRED : 默認(rèn)的事務(wù)傳播級(jí)別. 如果當(dāng)前存在事務(wù), 則加?該事務(wù). 如果當(dāng)前沒(méi)
有事務(wù), 則創(chuàng)建?個(gè)新的事務(wù).)
A有事務(wù),B就直接使用A的事務(wù),如果A沒(méi)有事務(wù),B創(chuàng)建一個(gè)事務(wù)
2. Propagation.SUPPORTS : 如果當(dāng)前存在事務(wù), 則加?該事務(wù). 如果當(dāng)前沒(méi)有事務(wù), 則以?事務(wù)的?式繼續(xù)運(yùn)?.
A有事務(wù),B就直接使用A的事務(wù),如果A沒(méi)有事務(wù),B以非事務(wù)的方式進(jìn)行運(yùn)行
3. Propagation.MANDATORY :強(qiáng)制性. 如果當(dāng)前存在事務(wù), 則加?該事務(wù). 如果當(dāng)前沒(méi)有事務(wù), 則
拋出異常.
A有事務(wù),B就直接使用A的事務(wù),如果A沒(méi)有事務(wù),那么就直接拋出異常
4. Propagation.REQUIRES_NEW : 創(chuàng)建?個(gè)新的事務(wù). 如果當(dāng)前存在事務(wù), 則把當(dāng)前事務(wù)掛起. 也
就是說(shuō)不管外部?法是否開(kāi)啟事務(wù), Propagation.REQUIRES_NEW 修飾的內(nèi)部?法都會(huì)新開(kāi)
啟??的事務(wù), 且開(kāi)啟的事務(wù)相互獨(dú)?, 互不?擾.
就是不管A有無(wú)事務(wù),B都創(chuàng)建新的事務(wù)
5. Propagation.NOT_SUPPORTED : 以?事務(wù)?式運(yùn)?, 如果當(dāng)前存在事務(wù), 則把當(dāng)前事務(wù)掛起(不?).
就是不管A有無(wú)事務(wù),B都直接以非事務(wù)的方式進(jìn)行運(yùn)行
6. Propagation.NEVER : 以?事務(wù)?式運(yùn)?, 如果當(dāng)前存在事務(wù), 則拋出異常
如果A事務(wù)存在,那么就直接拋出異常
7. Propagation.NESTED : 如果當(dāng)前存在事務(wù), 則創(chuàng)建?個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)?.
如果當(dāng)前沒(méi)有事務(wù), 則該取值等價(jià)于 PROPAGATION_REQUIRED
沒(méi)有事務(wù)就創(chuàng)建事務(wù),有的話就干點(diǎn)其他的事情
🚀2.4事務(wù)傳播機(jī)制代碼演示
2.4.1REQUIRED
controller控制層,代表的A
@RequestMapping("/user")
@RestController
public class UserController2 {@Autowiredprivate UserService userService;@Autowiredprivate LogService logService;@Transactional(propagation = Propagation.REQUIRED)@RequestMapping("/p1")public String r3(String name, String password) {//??注冊(cè)u(píng)serService.registUser(name, password);//記錄操作?志logService.insertLog(name, "??注冊(cè)");return "p1";}
}
其余兩個(gè)service:
登錄日志打印:
@Service
public class LogService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public void insertLog(String userName,String op){logInfoMapper.insert(userName,"用戶注冊(cè)");int a=10/0;}
}
user登錄?:
@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public Integer registUser(String userName, String password) {Integer result = userInfoMapper.insert(userName, password);return result;}
}
輸出情況,打印的日志如下:
1. p1 ?法開(kāi)始事務(wù)
2. ??注冊(cè), 插??條數(shù)據(jù) (執(zhí)?成功) (和p1 使?同?個(gè)事務(wù))
3. 記錄操作?志, 插??條數(shù)據(jù)(出現(xiàn)異常, 執(zhí)?失敗) (和p1 使?同?個(gè)事務(wù))
4. 因?yàn)椴襟E3出現(xiàn)異常, 事務(wù)回滾. 步驟2和3使?同?個(gè)事務(wù), 所以步驟2的數(shù)據(jù)也回滾了.?
?2.4.2REQUIRES_NEW
我們將這里的兩個(gè)service層改成REQUIRES_NEW
這里的其中一個(gè)事務(wù)進(jìn)行了提交;
另一個(gè)代碼存在算數(shù)異常的就沒(méi)有進(jìn)行提交
這里就是單獨(dú)創(chuàng)建了自己的事務(wù),這里的兩個(gè)service層創(chuàng)建的兩個(gè)事務(wù)就不會(huì)相互影響,所以其中一個(gè)提交,另一個(gè)進(jìn)行了回滾的操作;
2.4.3NEVER
我們將其中一個(gè)代碼傳播機(jī)制改變
@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;@Transactional(propagation = Propagation.NEVER)public Integer registUser(String userName, String password) {Integer result = userInfoMapper.insert(userName, password);return result;}
}
?輸出的日志如下所示:
那么這里可以看到報(bào)錯(cuò)信息就是A調(diào)用層存在事務(wù),導(dǎo)致?報(bào)錯(cuò);
2.4.4NESTED
將上述UserService 和LogService 中相關(guān)?法事務(wù)傳播機(jī)制改為 Propagation.NESTED
小編這里就不演示代碼了,大家可以自己去試一試;
打印日志如下:
由于是嵌套事務(wù), LogService 出現(xiàn)異常之后, 往上找調(diào)?它的?法和事務(wù), 所以??注冊(cè)也失敗
了.最終結(jié)果是兩個(gè)數(shù)據(jù)都沒(méi)有添加
p1事務(wù)可以認(rèn)為是?事務(wù), 嵌套事務(wù)是?事務(wù). ?事務(wù)出現(xiàn)異常, ?事務(wù)也會(huì)回滾, ?事務(wù)出現(xiàn)異常, 如果不進(jìn)?處理, 也會(huì)導(dǎo)致?事務(wù)回滾(可以認(rèn)為是REQUIRED,但是不完全是)
🚀2.5NESTED和REQUIRED 區(qū)別
我們知道,當(dāng)兩個(gè)方法不存在問(wèn)題時(shí),這里的兩種傳播機(jī)制是沒(méi)有啥區(qū)別的,但是當(dāng)出現(xiàn)問(wèn)題時(shí),我們可以發(fā)現(xiàn)情況如上圖所示,但是真的沒(méi)有區(qū)別嗎?答案是否定的;
@Service
public class LogService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.NESTED)public void insertLog(String userName,String op){try {int a=10/0;}catch (Exception e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}logInfoMapper.insert(userName,"用戶注冊(cè)"); }
}
重新運(yùn)?程序, 發(fā)現(xiàn)??表數(shù)據(jù)添加成功, ?志表添加失敗.
LogService 中的事務(wù)已經(jīng)回滾, 但是嵌套事務(wù)不會(huì)回滾嵌套之前的事務(wù), 也就是說(shuō)嵌套事務(wù)可以實(shí)
現(xiàn)部分事務(wù)回滾
但是對(duì)于REQUIRED 如果回滾就是回滾所有事務(wù), 不能實(shí)現(xiàn)部分事務(wù)的回滾. (因?yàn)閷儆谕?個(gè)事務(wù))?
嵌套事務(wù)之所以能夠?qū)崿F(xiàn)部分事務(wù)的回滾, 是因?yàn)槭聞?wù)中有?個(gè)保存點(diǎn)(savepoint)的概念, 嵌套事務(wù)進(jìn)?之后相當(dāng)于新建了?個(gè)保存點(diǎn), ?滾回時(shí)只回滾到當(dāng)前保存點(diǎn).
?
這里是小編的理解,大家有問(wèn)題或者質(zhì)疑可以私信我喲~~~
📚?3.總結(jié)
💬💬本期講解了關(guān)于MySQL事務(wù)的隔離級(jí)別回顧,以及spring的事務(wù)隔離級(jí)別以及事務(wù)傳播機(jī)制,分別從概念和代碼進(jìn)行了演示~~~
🌅🌅🌅~~~~最后希望與諸君共勉,共同進(jìn)步!!!
💪💪💪以上就是本期內(nèi)容了, 感興趣的話,就關(guān)注小編吧。
? ? ?? 😊😊??期待你的關(guān)注~~~