Spring事務(wù)管理原理及方法詳解
這篇文章主要介紹了Spring事務(wù)管理原理及方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
事務(wù),在日常開發(fā)或者面試中都必定會(huì)涉及到。開發(fā)工作中,結(jié)合數(shù)據(jù)庫(kù)開發(fā)理解就是:一組dml要么全部成功執(zhí)行提交,要么因?yàn)槟骋粋€(gè)操作異常,撤銷之前所做的成功的操作,整體執(zhí)行失敗。再簡(jiǎn)單點(diǎn)的一句話:生死與共。
由此,可以看出,事務(wù)的必要性:在開發(fā)工作中,保證操作數(shù)據(jù)的安全性。事務(wù)的控制也就是保證數(shù)據(jù)的訪問安全性。
一、事務(wù)的四大特性
A:原子性(atomicity),對(duì)數(shù)據(jù)的修改,要么全部成功執(zhí)行,要么全部不執(zhí)行。
C:一致性(consistency),一旦事務(wù)完成,系統(tǒng)必須保證數(shù)據(jù)職員是滿足業(yè)務(wù)狀態(tài)的一種一致狀態(tài)中。很難懂的解釋,跟原子性很像。一個(gè)事務(wù)在操作過程中,數(shù)據(jù)可能會(huì)產(chǎn)生很多中間態(tài),一致性保證中間態(tài)對(duì)其他事務(wù)不可見,因?yàn)檫@些中間態(tài),與事務(wù)的開始和結(jié)束的狀態(tài)是不一致的。也就是從一種正確的狀態(tài)到另一種正確的狀態(tài)。
I:隔離性(isolation),事務(wù)之間的執(zhí)行應(yīng)不相互影響,也即事務(wù)執(zhí)行的獨(dú)立。
D:持久性(durability),事務(wù)一旦提交,則對(duì)數(shù)據(jù)庫(kù)的修改是永久性的。
二、事務(wù)的隔離級(jí)別
并發(fā)環(huán)境下,事務(wù)可能會(huì)存在若干問題:臟讀、幻讀、不可重復(fù)讀、第一類更新丟失、第二類更新丟失。
類型 | 說明 | 舉例 |
臟讀 | A事務(wù)讀取到了B事務(wù)未提交的數(shù)據(jù) | A開啟事務(wù)=>B開啟事務(wù),讀取賬戶1000塊,取走100塊=>A讀取賬戶金額,讀取到900=>B回滾事務(wù)。此時(shí)A讀取的余額數(shù)據(jù)是無效的 |
幻讀 | 一個(gè)事務(wù)里面的操作發(fā)現(xiàn)了未被操作的數(shù)據(jù) |
A開啟事務(wù),修改某些數(shù)據(jù)狀態(tài)=>B開啟事務(wù),執(zhí)行新增數(shù)據(jù)并提交=>A事務(wù)提交,會(huì)出現(xiàn)一條未被修改的數(shù)據(jù)。 幻讀發(fā)生的前提是并發(fā)事務(wù)中發(fā)生了新增或者刪除動(dòng)作。 |
不可重復(fù)讀 | 一個(gè)事務(wù)中,先后兩次讀取數(shù)據(jù),讀到的結(jié)果不一致 |
A開啟事務(wù),讀取賬戶1000塊=>B開啟事務(wù),讀取賬戶1000塊,取出100塊并提交事務(wù)=>A再讀取賬戶余額,余額900塊。 一個(gè)事務(wù)范圍內(nèi)的兩次同樣的查詢,卻返回了兩次不同的數(shù)據(jù),這就是不可重復(fù)讀 |
第一類更新丟失 | A事務(wù)撤銷,把已經(jīng)提交的B事務(wù)的更新的數(shù)據(jù)覆蓋 | A開啟事務(wù),讀取賬戶1000塊=>B開啟事務(wù),讀取賬戶1000塊,然后增加100塊,提交事務(wù),賬戶變?yōu)?100=>A撤銷回滾事務(wù),賬戶成1000塊 |
第二類更新丟失 | A事務(wù)提交,把已經(jīng)提交的B事務(wù)的更新的數(shù)據(jù)覆蓋 | A開啟事務(wù),讀取賬戶1000塊=>B開啟事務(wù),讀取賬戶1000塊,然后增加100塊,提交事務(wù),賬戶變?yōu)?100=>A增加100塊,提交事務(wù),賬戶變?yōu)?100。 |
針對(duì)并發(fā)環(huán)境下可能出現(xiàn)的事務(wù)問題,于是就出現(xiàn)了隔離級(jí)別的解決方案,由低到高依次是:讀未提交(Read uncommitted)、讀已提交(Read committed)、可重復(fù)讀(Repeatable read)、串行序列化(serializable)。下表展示出不同的隔離級(jí)別,對(duì)于臟讀、幻讀、不可重復(fù)讀是否會(huì)出現(xiàn)。
類型 | 臟讀 | 不可重復(fù)讀 | 幻讀 | 說明 |
Read uncommitted | 會(huì) | 會(huì) | 會(huì) | |
Read committed | 不會(huì) | 會(huì) | 會(huì) | |
Repeatable read | 不會(huì) | 不會(huì) | 會(huì) | mysql的默認(rèn)隔離級(jí)別 |
serializable | 不會(huì) | 不會(huì) | 不會(huì) | 最嚴(yán)格的隔離級(jí)別,將事務(wù)串行化執(zhí)行,性能低。 |
mysql中查詢當(dāng)前隔離級(jí)別:select @@tx_isolation;
三、spring事務(wù)支持的隔離級(jí)別和傳播特性
spring中定義了五種隔離界別和七種傳播行為(可以在org.springframework.transaction.TransactionDefinition類中看到詳細(xì)的解釋)
1、spring支持的隔離級(jí)別
ISOLATION_DEFAULT:默認(rèn)級(jí)別。一般是使用的是數(shù)據(jù)庫(kù)本身的隔離級(jí)別(mysql - Repeatable read 、oracle - Read committed)
余下ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE分別對(duì)應(yīng)上述數(shù)據(jù)庫(kù)隔離級(jí)別配置。
2、傳播特性
事務(wù)的傳播特性就是在多個(gè)事務(wù)方法互相調(diào)用的時(shí)候,事務(wù)該如何在方法之間使用傳播:
- PROPAGATION_REQUIRED:如果當(dāng)前有事務(wù),則加入該事務(wù)中。如果沒有,則新建事務(wù)。
- PROPAGATION_SUPPORTS:如果當(dāng)前有事務(wù),則加入該事務(wù)中。如果沒有,則以非事務(wù)狀態(tài)運(yùn)行。
- PROPAGATION_MANDATORY:如果當(dāng)前有事務(wù),則加入該事務(wù)中。如果沒有,則拋出無事務(wù)異常
- PROPAGATION_REQUIRES_NEW:新建事務(wù)。如果當(dāng)前存在事務(wù),則掛起該事務(wù)。
- PROPAGATION_NOT_SUPPORTED:非事務(wù)狀態(tài)運(yùn)行。如果當(dāng)前存在事務(wù),則掛起該事務(wù)。
- PROPAGATION_NEVER:非事務(wù)狀態(tài)運(yùn)行。如果當(dāng)前存在事務(wù),則拋出異常。
- PROPAGATION_NESTED:如果當(dāng)前有事務(wù),則嵌套事務(wù)(父子事務(wù))執(zhí)行。如果沒有,類似PROPAGATION_REQUIRED處理。
spring默認(rèn)的傳播行為是PROPAGATION_REQUIRED,一般適用于絕大多數(shù)的開發(fā)工作。
3、事務(wù)的超時(shí)屬性
事務(wù)在超過預(yù)定時(shí)間內(nèi)還未完成操作,則自動(dòng)回滾事務(wù)。TransactionDefinition 中以int值來表示超時(shí)時(shí)間,單位是秒,提供的默認(rèn)值是TIMEOUT_DEFAULT = -1,即永不超時(shí),一直等待操作完成
四、spring事務(wù)配置方法
spring并不具體直接的管理事務(wù),而是提供了一個(gè)接口org.springframework.transaction.PlatformTransactionManager,該接口中主要定義了三個(gè)方法:getTransaction(獲取事務(wù))、commit(提交)和rollback(回滾)。
根據(jù)不同的持久化策略,spring提供了不同的實(shí)現(xiàn),比如jdbc -
org.springframework.jdbc.datasource.DataSourceTransactionManager、hibernate - org.springframework.orm.hibernate5.HibernateTransactionManager等,在其他的實(shí)現(xiàn)可以通過源碼去查詢。
spring事務(wù)使用,可以分為編程式事務(wù)和聲明式事務(wù)。編程式事務(wù)每次業(yè)務(wù)使用都得書寫獲取事務(wù)、設(shè)置事務(wù)隔離級(jí)別和傳播特性、提交或回滾事務(wù),代碼的重復(fù)太高,費(fèi)時(shí)費(fèi)力,且如果代碼的功能性復(fù)雜時(shí)候,使用編程式變得更加痛苦。而聲明式的事務(wù),屬于無侵入式的,不會(huì)影響主業(yè)務(wù)流程,且編寫上非常簡(jiǎn)單。所以目前開發(fā)工作中,更多的是使用聲明式事務(wù)。
1、編程式事務(wù)
//to do。后續(xù)補(bǔ)充
2、聲明式事務(wù)
聲明式事務(wù)分為兩種:基于aop的織入和@Transactional的注解。
2.1、基于aop的事務(wù)織入
之后在servcie中定義方法,最好的就是tx:method中定義的格式開頭,就會(huì)執(zhí)行特定的事務(wù)。
2.2、注解事務(wù)
注解事務(wù)第一部分的數(shù)據(jù)源和事務(wù)管理器配置同上,配置文件中需要修改的是開啟注解配置:
然后在service編程中,加注解@Transactional即可(建議只在service實(shí)現(xiàn)類中加),如下是配置樣例,其中的屬性可以按需設(shè)置:
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 100, readOnly = false, rollbackFor = {},noRollbackFor = {})
注意點(diǎn):
事務(wù)的異?;貪L只檢查RuntimeException的異常,checked exception(如ClassNotFoundException、FileNotFoundException等)不會(huì)滾,捕獲異常不拋出也不會(huì)回滾。
五、spring和springmvc父子容器
現(xiàn)在開發(fā)工作中,一般大多數(shù)都使用的spring和springmvc構(gòu)建,這里,spring容器和springmvc容器就構(gòu)成了父子容器的關(guān)系。父容器spring是發(fā)現(xiàn)不了子容器springmvc中的bean的,而子容器可以發(fā)現(xiàn)父容器中注冊(cè)的bean。由此,實(shí)際開發(fā)工作中,不注意的話,往往會(huì)產(chǎn)生一些意想不到的問題。
首先,通常我們配置spring配置文件applicationContext.xml的時(shí)候,會(huì)配置如下的掃描:
<context:component-scan base-package="com.cfang" />
這個(gè)配置會(huì)掃描指定包下面的所有@Component類型注解,包括@Controller,@Service,@Respository,并將掃描到的bean注冊(cè)到spring容器中。
一般,spring配置文件中,還會(huì)出現(xiàn)下面的配置,作用是掃描@Required、@Autowired、 @PostConstruct、@PersistenceContext、@Resource、@PreDestroy等注解。理論上,此配置為可選配置,因?yàn)樯厦娴膾呙枧渲脮?huì)默認(rèn)打開。
<context:annotation-config/>
接下來配置springmvc的配置文件spring-mvc.xml,配置掃描注解@RequestMapping、@RequestBody、@ResponseBody等,同時(shí),該配置默認(rèn)加載很多參數(shù)綁定方法 。
<mvc:annotation-driven />
上面一句話,相當(dāng)于:
<!--配置注解控制器映射器,它是SpringMVC中用來將Request請(qǐng)求URL到映射到具體Controller--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--配置注解控制器映射器,它是SpringMVC中用來將具體請(qǐng)求映射到具體方法--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
上面聊完基本配置,以下梳理下,來了解可能產(chǎn)生的容器沖突,對(duì)于事務(wù)管理的影響。
首先,有兩個(gè)基本的容器:spring和springmvc,配置文件分別為applicationContext.xml和spring-mvc.xml
1、applicationContext.xml中配置<context:component-scan base-package="com.cfang" />,掃描指定包下的所有bean,并自動(dòng)注冊(cè)到spring容器中
2、spring-mvc.xml配置<mvc:annotation-driven />,掃描相關(guān)的springmvc的注解
3、為了保證springmvc的正常跳轉(zhuǎn),通常我們還得在spring-mvc.xml文件中配置包掃描<context:component-scan base-package="com.cfang" />。
按照以上配置信息,就會(huì)產(chǎn)生事務(wù)失效。原因就在于:
Spring容器優(yōu)先加載由ServletContextListener(對(duì)應(yīng)applicationContext.xml)產(chǎn)生的父容器,
而SpringMVC(對(duì)應(yīng)spring-mvc.xml)產(chǎn)生的是子容器。子容器Controller進(jìn)行掃描裝配時(shí)裝配的@Service注解的實(shí)例是沒有經(jīng)過事務(wù)加強(qiáng)處理,即沒有事務(wù)處理能力的Service,
而父容器進(jìn)行初始化的Service是保證事務(wù)的增強(qiáng)處理能力的。如果不在子容器中將Service排除(exclude)掉,此時(shí)得到的將是無事務(wù)處理能力的Service。
解決辦法按照官方建議的來配置,各自負(fù)責(zé)一部分加載:
spring掃描:
<context:component-scan base-package="com.cfang.WeChat" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
springmvc掃描:
<context:component-scan base-package="com.cfang.WeChat" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Spring聲明式事務(wù)注解之@EnableTransactionManagement解析
- spring學(xué)習(xí)JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理
- Spring框架JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理完全注解方式
- 解析spring事務(wù)管理@Transactional為什么要添加rollbackFor=Exception.class
- SpringBoot2整合JTA組件實(shí)現(xiàn)多數(shù)據(jù)源事務(wù)管理
- 五分鐘教你手寫 SpringBoot 本地事務(wù)管理實(shí)現(xiàn)
- 啟用Spring事務(wù)管理@EnableTransactionManagement示例解析
相關(guān)文章
Spring Boot @Conditional注解用法示例介紹
這篇文章主要給大家介紹了關(guān)于Spring Boot @Conditional注解用法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11java JDBC主要組件連接數(shù)據(jù)庫(kù)及執(zhí)行SQL過程示例全面詳解
這篇文章主要為大家介紹了java JDBC主要組件連接數(shù)據(jù)庫(kù)及執(zhí)行SQL的過程示例全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Java Char的簡(jiǎn)單工具類CharUtil分享
下面小編就為大家分享一篇Java Char的簡(jiǎn)單工具類CharUtil,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12java web請(qǐng)求和響應(yīng)中出現(xiàn)中文亂碼問題的解析
這篇文章主要為大家解析了java web請(qǐng)求和響應(yīng)中出現(xiàn)中文亂碼問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼
這篇文章主要介紹了springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04Java中的ArrayList、LinkedList、HashSet等容器詳解
這篇文章主要介紹了Java中的ArrayList、LinkedList、HashSet等容器詳解,集合表示一組對(duì)象,稱為其元素,有些集合允許重復(fù)元素,而另一些則不允許,有些是有序的,有些是無序的,需要的朋友可以參考下2023-08-08