Spring聲明式事務(wù)配置使用詳解
序章
Spring 框架對 JDBC 進(jìn)行封裝,使用 JdbcTemplate 方便實(shí)現(xiàn)對數(shù)據(jù)庫操作
準(zhǔn)備工作
<dependencies> <!-- 基于Maven依賴傳遞性,導(dǎo)入spring-context依賴即可導(dǎo)入當(dāng)前所需所有jar包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.1</version> </dependency> <!-- Spring 持久化層支持jar包 --> <!-- Spring 在執(zhí)行持久化層操作、與持久化層技術(shù)進(jìn)行整合過程中,需要使用orm、jdbc、tx三個(gè) jar包 --> <!-- 導(dǎo)入 orm 包就可以通過 Maven 的依賴傳遞性把其他兩個(gè)也導(dǎo)入 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.3.1</version> </dependency> <!-- Spring 測試相關(guān) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.1</version> </dependency> <!-- junit測試 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- MySQL驅(qū)動(dòng) --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <!-- 數(shù)據(jù)源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.31</version> </dependency> </dependencies>
創(chuàng)建jdbc.properties
jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.driver=com.mysql.cj.jdbc.Driver
配置Spring的配置文件
<!--導(dǎo)入外部屬性文件--> <context:property-placeholderlocation="classpath:jdbc.properties"/> <!--配置數(shù)據(jù)源--> <beanid="druidDataSource"class="com.alibaba.druid.pool.DruidDataSource"> <propertyname="url"value="${atguigu.url}"/> <propertyname="driverClassName"value="${atguigu.driver}"/> <propertyname="username"value="${atguigu.username}"/> <propertyname="password"value="${atguigu.password}"/> </bean> <!--配置JdbcTemplate--> <beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"> <!--裝配數(shù)據(jù)源--> <propertyname="dataSource"ref="druidDataSource"/> </bean>
聲明式事務(wù)概念
編程式的實(shí)現(xiàn)方式存在缺陷:
細(xì)節(jié)沒有被屏蔽:具體操作過程中,所有細(xì)節(jié)都需要程序員自己來完成,比較繁瑣。
代碼復(fù)用性不高:如果沒有有效抽取出來,每次實(shí)現(xiàn)功能都需要自己編寫代碼,代碼就沒有得到復(fù) 用。
聲明式事務(wù)
既然事務(wù)控制的代碼有規(guī)律可循,代碼的結(jié)構(gòu)基本是確定的,所以框架就可以將固定模式的代碼抽取出來,進(jìn)行相關(guān)的封裝。
封裝起來后,我們只需要在配置文件中進(jìn)行簡單的配置即可完成操作。
好處1:提高開發(fā)效率
好處2:消除了冗余的代碼
好處3:框架會(huì)綜合考慮相關(guān)領(lǐng)域中在實(shí)際開發(fā)環(huán)境下有可能遇到的各種問題,進(jìn)行了健壯性、性 能等各個(gè)方面的優(yōu)化
代碼講解
配置 Spring 的配置文件
<!--掃描組件--> <context:component-scanbase-package="com.atguigu.spring.tx.annotation"> </context:component-scan> <!--導(dǎo)入外部屬性文件--> <context:property-placeholderlocation="classpath:jdbc.properties"/> <!--配置數(shù)據(jù)源--> <beanid="druidDataSource"class="com.alibaba.druid.pool.DruidDataSource"> <propertyname="url"value="${jdbc.url}"/> <propertyname="driverClassName"value="${jdbc.driver}"/> <propertyname="username"value="${jdbc.username}"/> <propertyname="password"value="${jdbc.password}"/> </bean> <!--配置JdbcTemplate--> <beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"> <!--裝配數(shù)據(jù)源--> <propertyname="dataSource"ref="druidDataSource"/> </bean>
創(chuàng)建表
REATETABLE`t_book`( book_id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'主鍵', `book_name`varchar(20)DEFAULTNULLCOMMENT'圖書名稱', `price`int(11)DEFAULTNULLCOMMENT'價(jià)格', `stock`int(10)unsignedDEFAULTNULLCOMMENT'庫存(無符號(hào))', PRIMARYKEY(`book_id`) )ENGINE=InnoDBAUTO_INCREMENT=3DEFAULTCHARSET=utf8; insert into`t_book`(`book_id`,`book_name`,`price`,`stock`)values(1,'斗破蒼穹',80,100),(2,'斗羅大陸',50,100); CREATETABLE`t_user`( `user_id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'主鍵', `username`varchar(20)DEFAULTNULLCOMMENT'用戶名', `balance`int(10)unsignedDEFAULTNULLCOMMENT'余額(無符號(hào))', PRIMARYKEY(`user_id`) )ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8; insert into`t_user`(`user_id`,`username`,`balance`)values(1,'admin',50);
創(chuàng)建組件
創(chuàng)建BookController:
@Controller public class BookController { @Autowired private BookService bookService; public void buyBook(Integer bookId, Integer userId){ bookService.buyBook(bookId, userId); } }
創(chuàng)建接口BookService:
public interface BookService { void buyBook(Integer bookId, Integer userId); }
創(chuàng)建實(shí)現(xiàn)類BookServiceImpl:
測試無事務(wù)情況
②模擬場景
用戶購買圖書,先查詢圖書的價(jià)格,再更新圖書的庫存和用戶的余額
假設(shè)用戶id為1的用戶,購買id為1的圖書
用戶余額為50,而圖書價(jià)格為80
購買圖書之后,用戶的余額為-30,數(shù)據(jù)庫中余額字段設(shè)置了無符號(hào),因此無法將-30插入到余額字段
此時(shí)執(zhí)行sql語句會(huì)拋出SQLException
③觀察結(jié)果
因?yàn)闆]有添加事務(wù),圖書的庫存更新了,但是用戶的余額沒有更新
顯然這樣的結(jié)果是錯(cuò)誤的,購買圖書是一個(gè)完整的功能,更新庫存和更新余額要么都成功要么都失敗
加入事務(wù)
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 開啟事務(wù)的注解驅(qū)動(dòng) 通過注解@Transactional所標(biāo)識(shí)的方法或標(biāo)識(shí)的類中所有的方法,都會(huì)被事務(wù)管理器管理事務(wù) --> <!-- transaction-manager屬性的默認(rèn)值是transactionManager,如果事務(wù)管理器bean的id正好就 是這個(gè)默認(rèn)值,則可以省略這個(gè)屬性 --> <tx:annotation-driven transaction-manager="transactionManager" />
注意:導(dǎo)入的名稱空間需要 tx 結(jié)尾的那個(gè)。
添加事務(wù)注解
因?yàn)閟ervice層表示業(yè)務(wù)邏輯層,一個(gè)方法表示一個(gè)完成的功能,因此處理事務(wù)一般在service層處理在BookServiceImpl的buybook()添加注解@Transactiona
觀察結(jié)果
由于使用了Spring的聲明式事務(wù),更新庫存和更新余額都沒有執(zhí)行
@Transactional注解標(biāo)識(shí)的位置
@Transactional標(biāo)識(shí)在方法上,咋只會(huì)影響該方法
@Transactional標(biāo)識(shí)的類上,咋會(huì)影響類中所有的方法
事務(wù)屬性:只讀
對一個(gè)查詢操作來說,如果我們把它設(shè)置成只讀,就能夠明確告訴數(shù)據(jù)庫,這個(gè)操作不涉及寫操作。這樣數(shù)據(jù)庫就能夠針對查詢操作來進(jìn)行優(yōu)化。
事務(wù)屬性:超時(shí)
事務(wù)在執(zhí)行過程中,有可能因?yàn)橛龅侥承﹩栴},導(dǎo)致程序卡住,從而長時(shí)間占用數(shù)據(jù)庫資源。而長時(shí)間占用資源,大概率是因?yàn)槌绦蜻\(yùn)行出現(xiàn)了問題(可能是Java程序或MySQL數(shù)據(jù)庫或網(wǎng)絡(luò)連接等等)。
此時(shí)這個(gè)很可能出問題的程序應(yīng)該被回滾,撤銷它已做的操作,事務(wù)結(jié)束,把資源讓出來,讓其他正常程序可以執(zhí)行
概括來說就是一句話:超時(shí)回滾,釋放資源。
事務(wù)屬性:回滾策略
聲明式事務(wù)默認(rèn)只針對運(yùn)行時(shí)異?;貪L,編譯時(shí)異常不回滾。
可以通過@Transactional中相關(guān)屬性設(shè)置回滾策略
rollbackFor屬性:需要設(shè)置一個(gè)Class類型的對象
rollbackForClassName屬性:需要設(shè)置一個(gè)字符串類型的全類名
noRollbackFor屬性:需要設(shè)置一個(gè)Class類型的對象
rollbackFor屬性:需要設(shè)置一個(gè)字符串類型的全類名
事務(wù)屬性:事務(wù)隔離級(jí)別
數(shù)據(jù)庫系統(tǒng)必須具有隔離并發(fā)運(yùn)行各個(gè)事務(wù)的能力,使它們不會(huì)相互影響,避免各種并發(fā)問題。一個(gè)事務(wù)與其他事務(wù)隔離的程度稱為隔離級(jí)別。SQL標(biāo)準(zhǔn)中規(guī)定了多種事務(wù)隔離級(jí)別,不同隔離級(jí)別對應(yīng)不同的干擾程度,隔離級(jí)別越高,數(shù)據(jù)一致性就越好,但并發(fā)性越弱。
隔離級(jí)別一共有四種:
讀未提交:READ UNCOMMITTED
允許Transaction01讀取Transaction02未提交的修改。
讀已提交:READ COMMITTED、
要求Transaction01只能讀取Transaction02已提交的修改。
可重復(fù)讀:REPEATABLE READ
確保Transaction01可以多次從一個(gè)字段中讀取到相同的值,即Transaction01執(zhí)行期間禁止其它
事務(wù)對這個(gè)字段進(jìn)行更新。
串行化:SERIALIZABLE
確保Transaction01可以多次從一個(gè)表中讀取到相同的行,在Transaction01執(zhí)行期間,禁止其它
事務(wù)對這個(gè)表進(jìn)行添加、更新、刪除操作??梢员苊馊魏尾l(fā)問題,但性能十分低下。
@Transactional(isolation = Isolation.DEFAULT)//使用數(shù)據(jù)庫默認(rèn)的隔離級(jí)別 @Transactional(isolation = Isolation.READ_UNCOMMITTED)//讀未提交 @Transactional(isolation = Isolation.READ_COMMITTED)//讀已提交 @Transactional(isolation = Isolation.REPEATABLE_READ)//可重復(fù)讀 @Transactional(isolation = Isolation.SERIALIZABLE)//串行化
事務(wù)屬性:事務(wù)傳播行為
當(dāng)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),必須指定事務(wù)應(yīng)該如何傳播。例如:方法可能繼續(xù)在現(xiàn)有事務(wù)中運(yùn)行,也可能開啟一個(gè)新事務(wù),并在自己的事務(wù)中運(yùn)行。
可以通過@Transactional中的propagation屬性設(shè)置事務(wù)傳播行為
修改BookServiceImpl中buyBook()上,注解@Transactional的propagation屬性
@Transactional(propagation = Propagation.REQUIRED),默認(rèn)情況,表示如果當(dāng)前線程上有已經(jīng)開啟的事務(wù)可用,那么就在這個(gè)事務(wù)中運(yùn)行。經(jīng)過觀察,購買圖書的方法buyBook()在checkout()中被調(diào)用,checkout()上有事務(wù)注解,因此在此事務(wù)中執(zhí)行。所購買的兩本圖書的價(jià)格為80和50,而用戶的余額為100,因此在購買第二本圖書時(shí)余額不足失敗,導(dǎo)致整個(gè)checkout()回滾,即只要有一本書買不了,就都買不了
@Transactional(propagation = Propagation.REQUIRES_NEW),表示不管當(dāng)前線程上是否有已經(jīng)開啟的事務(wù),都要開啟新事務(wù)。同樣的場景,每次購買圖書都是在buyBook()的事務(wù)中執(zhí)行,因此第一本圖書購買成功,事務(wù)結(jié)束,第二本圖書購買失敗,只在第二次的buyBook()中回滾,購買第一本圖書不受影響,即能買幾本就買幾本
到此這篇關(guān)于Spring聲明式事務(wù)配置使用詳解的文章就介紹到這了,更多相關(guān)Spring聲明式事務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springBoot server.port=-1的含義說明
這篇文章主要介紹了springBoot server.port=-1的含義說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08基于Java驗(yàn)證jwt token代碼實(shí)例
這篇文章主要介紹了基于Java驗(yàn)證jwt token代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Java由淺入深細(xì)數(shù)數(shù)組的操作下
數(shù)組對于每一門編程語言來說都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語言對數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java?語言中提供的數(shù)組是用來存儲(chǔ)固定大小的同類型元素2022-04-04簡單講解Java設(shè)計(jì)模式編程中的單一職責(zé)原則
這篇文章主要介紹了Java設(shè)計(jì)模式編程中的單一職責(zé)原則,這在團(tuán)隊(duì)開發(fā)編寫接口時(shí)經(jīng)常使用這樣的約定,需要的朋友可以參考下2016-02-02java實(shí)現(xiàn)學(xué)生宿舍系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)生宿舍系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03JAVA WSIMPORT生成WEBSERVICE客戶端401認(rèn)證過程圖解
這篇文章主要介紹了JAVA WSIMPORT生成WEBSERVICE客戶端401認(rèn)證過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10SpringBoot如何優(yōu)雅的整合Swagger Api自動(dòng)生成文檔
在多人協(xié)作的開發(fā)過程中,API文檔不僅可以減少等待,也能保證開發(fā)的持續(xù)進(jìn)行,這篇文章主要給大家介紹了關(guān)于SpringBoot如何優(yōu)雅的整合Swagger Api自動(dòng)生成文檔的相關(guān)資料,需要的朋友可以參考下2021-07-07JavaWeb?Servlet技術(shù)及其應(yīng)用實(shí)踐
這篇文章主要介紹了JavaWeb?Servlet技術(shù),Servlet指在服務(wù)器端執(zhí)行的一段Java代碼,可以接收用戶的請求和返回給用戶響應(yīng)結(jié)果,感興趣想要詳細(xì)了解可以參考下文2023-05-05