javascript
使用Spring框架实现数据库事务处理
企業(yè)級應(yīng)用系統(tǒng)在更新數(shù)據(jù)庫數(shù)據(jù)時,一般都采用數(shù)據(jù)庫事務(wù)處理,以確保數(shù)據(jù)庫數(shù)據(jù)的一致性。本文主要討論在Spring框架中如何使用數(shù)據(jù)庫事務(wù)處理更新數(shù)據(jù)庫數(shù)據(jù)。通過本課的學(xué)習(xí),可以達(dá)到如下目標(biāo)。
● 了解JDBC對數(shù)據(jù)庫事務(wù)處理的支持
● 掌握在Spring框架中使用事務(wù)處理的技術(shù)
事務(wù)處理對數(shù)據(jù)庫來說,是對數(shù)據(jù)庫的一系列SQL語句操作,這些操作被組織為一個事務(wù)。事務(wù)具有原子性,即事物中的操作要么全部執(zhí)行,要么全部不執(zhí)行。若事務(wù)中的SQL語句在執(zhí)行過程中發(fā)生錯誤,事務(wù)需要對已經(jīng)執(zhí)行的SQL語句進(jìn)行回滾操作,撤銷先前對數(shù)據(jù)庫的操作,防止數(shù)據(jù)庫出現(xiàn)錯誤狀態(tài)。
例如,在課程案例mooc數(shù)據(jù)庫中,一個業(yè)務(wù)是學(xué)生購買課程,購買課程業(yè)務(wù)步驟包括更新teacher表,記錄老師的收入,同時student_course表增加一條購買記錄,更新student表的余額字段。上述業(yè)務(wù)步驟需要全部執(zhí)行完畢,才能反映出學(xué)生購買課程的正確狀態(tài)。如果因意外情況,上述操作僅成功執(zhí)行了部分SQL語句,其它語句沒有執(zhí)行或執(zhí)行失敗,就會造成學(xué)生購買課程這個業(yè)務(wù)記錄不完整,數(shù)據(jù)庫處于數(shù)據(jù)錯亂狀態(tài)。若利用數(shù)據(jù)庫事務(wù)技術(shù)執(zhí)行上述操作,當(dāng)發(fā)生上述情況時,數(shù)據(jù)庫系統(tǒng)會將先前執(zhí)行的SQL語句撤銷,將數(shù)據(jù)庫回滾到事務(wù)執(zhí)行前狀態(tài)。
?
1、JDBC對數(shù)據(jù)庫事務(wù)處理的支持
JDBC本身就提供了對數(shù)據(jù)庫事務(wù)處理的支持,使用java.sql.Connection對象完成事務(wù)的提交。使用Connection提交數(shù)據(jù)庫事務(wù)處理代碼如下。
?
Connection類的setAutoCommit方法用于設(shè)置JDBC提交SQL語句的方式。設(shè)置為ture時,JDBC自動提交SQL語句,JDBC提交SQL語句的方式默認(rèn)為true。設(shè)置為false時,SQL語句的提交由應(yīng)用程序負(fù)責(zé),應(yīng)用程序必須調(diào)用commit方法,同時要在執(zhí)行SQL語句異常處理塊中調(diào)用rollback方法,對異常發(fā)生前進(jìn)行的數(shù)據(jù)庫進(jìn)行回滾操作。
在企業(yè)級應(yīng)用中,事務(wù)一般是并發(fā)執(zhí)行的,當(dāng)事務(wù)并發(fā)執(zhí)行時,就會發(fā)生數(shù)據(jù)庫數(shù)據(jù)同步的問題,具體問題可分為下面四種類型。
(1)臟讀:一個數(shù)據(jù)庫事務(wù)在更新數(shù)據(jù)的過程中,數(shù)據(jù)是保存在內(nèi)存中的,只有調(diào)用commit方法,更新的數(shù)據(jù)才最終寫到數(shù)據(jù)庫中。如果一個事務(wù)使用了另一個事務(wù)更新但沒保存的數(shù)據(jù),這個數(shù)據(jù)就稱為臟數(shù)據(jù),事務(wù)讀取這個數(shù)據(jù)就稱為臟讀。
(2)不可重復(fù)讀:在同一事務(wù)中,兩次讀取同一記錄,讀取的記錄內(nèi)容卻不相同。例如,事務(wù)A第一次讀取了一條記錄,同時事務(wù)B更新并提交了該條記錄,事務(wù)A第二次讀取該條記錄時,當(dāng)前讀取的記錄內(nèi)容和第一次讀取的記錄內(nèi)容不相同。
(3)幻讀:當(dāng)事務(wù)A對表中的所有記錄進(jìn)行了修改,同時事務(wù)B又在表中插入了一條新的記錄。A事務(wù)在后續(xù)對該表操作時,就會發(fā)現(xiàn)表中還存在沒有修改的記錄,就好象發(fā)生了幻覺一樣。
(4)丟失更新:當(dāng)事務(wù)A和事務(wù)B對同一數(shù)據(jù)進(jìn)行修改時,就會發(fā)生丟失更新的問題。例如,B事務(wù)對m記錄進(jìn)行了修改,A事務(wù)在修改m記錄時發(fā)生異常并回滾,就會將B事務(wù)對m記錄的修改覆蓋掉。
為了解決上面提到的事務(wù)并發(fā)問題,JDBC定義了五種事務(wù)隔離級別來解決來解決這些并發(fā)導(dǎo)致的問題。
表1 JDBC提供的事務(wù)隔離級別說明
?
表中隔離級別從上到下依次增高,最高級別是TRANSACTION_SERIALIZABLE,它通過強(qiáng)制事務(wù)串行執(zhí)行(不是并行),避免了事務(wù)并發(fā)執(zhí)行導(dǎo)致發(fā)生的數(shù)據(jù)同步問題。出于應(yīng)用程序訪問數(shù)據(jù)庫性能的考慮,一般設(shè)置隔離級別為TRANSACTION_READ_COMMITTED。
?
2、在Spring框架中調(diào)用事務(wù)處理
下面給出具體執(zhí)行事務(wù)處理的案例程序。案例程序的數(shù)據(jù)源采用mooc數(shù)據(jù)庫,mooc數(shù)據(jù)庫的結(jié)構(gòu)以及本案例中沒有列出的代碼詳見《Spring使用JDBC訪問MySQL數(shù)據(jù)庫》一文。
讓Spring框架開始執(zhí)行一個數(shù)據(jù)庫事務(wù)時,需要分成三步走。第一步配置數(shù)據(jù)源DataSource;第二步聲明事務(wù)管理TransactionManager類;第三步定義可以執(zhí)行事務(wù)的DAO類。
第一步:配置數(shù)據(jù)源DataSource
需要讓Spring框架知道數(shù)據(jù)庫的位置及其連接方式,這個工作由DataSource完成。Spring框架通過DataSource連接數(shù)據(jù)庫,DataSource既可以在Spring框架的配置文件中配置,也可以放在Bean類中配置。下面是在Spring配置文件中配置數(shù)據(jù)源的代碼。
?
配置語句定義了MySQL數(shù)據(jù)庫的URL地址、訪問賬戶及訪問密碼。
第二步:聲明事務(wù)管理TransactionManager
Spring 框架提供了PlatformTransactionManager作為事務(wù)管理類的頂層接口,聲明了初始化事務(wù)、提交事務(wù)、回滾事務(wù)等接口。接口實(shí)現(xiàn)由具體的數(shù)據(jù)庫驅(qū)動類實(shí)現(xiàn)。具體包括DataSourceTransactionManager、HibernateTransactionManager等實(shí)現(xiàn)類。本文主要用DataSourceTransactionManager來實(shí)現(xiàn)事務(wù)的管理。在Spring框架配置文件中配置DataSourceTransactionManager類。
?
聲明DataSourceTransactionManager類,需要傳入之前已聲明的DataSource數(shù)據(jù)源。
第三步:定義可以執(zhí)行事務(wù)的DAO類
DAO提供了應(yīng)用程序訪問數(shù)據(jù)源必要的接口和方法,接口和方法的具體實(shí)現(xiàn)細(xì)節(jié),程序并不需要了解。DAO的具體細(xì)節(jié)詳見《Spring使用JDBC訪問MySQL數(shù)據(jù)庫》一文。
?
CourseTransactio類實(shí)現(xiàn)了CourseDao接口,CourseDao是訪問mooc數(shù)據(jù)庫的頂層接口,接口提供了mooc數(shù)據(jù)庫表的增刪改查操作。CourseTransactio主要實(shí)現(xiàn)了CourseDao類的buyCourse,實(shí)現(xiàn)學(xué)生購買課程事務(wù)。購買課程事務(wù)涉及到更新teacher表,在student_course表增加一條購買記錄,更新student表的余額字段數(shù)據(jù)庫操作,這些操作需要進(jìn)行連續(xù)處理,中間不能中斷出錯,如果出錯則需要做回滾處理。 因此,buyCourse方法采用數(shù)據(jù)庫事務(wù)進(jìn)行處理。
事務(wù)處理從TransactionDefinition開始,前面我們談到了事務(wù)的隔離級別,TransactionDefinition就是用來定義事務(wù)隔離級別的。DefaultTransactionDefinition表示使用數(shù)據(jù)庫的默認(rèn)隔離級別,對大部分?jǐn)?shù)據(jù)庫而言,默認(rèn)隔離級別是TRANSACTION_READ_COMMITTED。
當(dāng)TransactionDefinition 創(chuàng)建后,可以通過調(diào)用 getTransaction方法開始事務(wù),該方法會返回 TransactionStatus 的一個實(shí)例。 TransactionStatus 用于追蹤當(dāng)前的事務(wù)狀態(tài),如果后面的SQL語句都運(yùn)行成功,可以使用 TransactionManager 的 commit() 方法來提交這個事務(wù),否則使用 rollback() 方法來回滾整個操作。
完整的配置文件代碼。
?
學(xué)生實(shí)體類代碼。
?
?
老師實(shí)體類代碼。
?
student表映射到學(xué)生實(shí)體類。
?
teacher表映射到老師實(shí)體類。
?
測試類代碼。
?
課程小結(jié)
(1)事務(wù)處理對數(shù)據(jù)庫來說,是對數(shù)據(jù)庫的一系列SQL語句操作,這些操作被組織為一個事務(wù)。事務(wù)具有原子性,即事物中的操作要么全部執(zhí)行,要么全部不執(zhí)行。若事務(wù)中的SQL語句在執(zhí)行過程中發(fā)生錯誤時,事務(wù)需要對已經(jīng)執(zhí)行的SQL語句進(jìn)行回滾操作,撤銷先前對數(shù)據(jù)庫的操作,防止數(shù)據(jù)庫出現(xiàn)錯誤狀態(tài)。
(2)讓Spring框架開始執(zhí)行一個數(shù)據(jù)庫事務(wù)時,需要分成三步走。第一步配置數(shù)據(jù)源DataSource;第二步聲明事務(wù)管理TransactionManager類;第三步定義可以執(zhí)行事務(wù)的DAO類。
總結(jié)
以上是生活随笔為你收集整理的使用Spring框架实现数据库事务处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java】睡眠排序
- 下一篇: Spring框架如何加载和定义Sprin