企業級應用系統在更新資料庫數據時,一般都採用資料庫事務處理,以確保資料庫數據的一致性。本文主要討論在Spring框架中如何使用資料庫事務處理更新資料庫數據。通過本課的學習,可以達到如下目標。
● 了解JDBC對資料庫事務處理的支持
● 掌握在Spring框架中使用事務處理的技術
事務處理對資料庫來說,是對資料庫的一系列SQL語句操作,這些操作被組織為一個事務。事務具有原子性,即事物中的操作要麼全部執行,要麼全部不執行。若事務中的SQL語句在執行過程中發生錯誤,事務需要對已經執行的SQL語句進行回滾操作,撤銷先前對資料庫的操作,防止資料庫出現錯誤狀態。
例如,在課程案例mooc資料庫中,一個業務是學生購買課程,購買課程業務步驟包括更新teacher表,記錄老師的收入,同時student_course表增加一條購買記錄,更新student表的餘額欄位。上述業務步驟需要全部執行完畢,才能反映出學生購買課程的正確狀態。如果因意外情況,上述操作僅成功執行了部分SQL語句,其它語句沒有執行或執行失敗,就會造成學生購買課程這個業務記錄不完整,資料庫處於數據錯亂狀態。若利用資料庫事務技術執行上述操作,當發生上述情況時,資料庫系統會將先前執行的SQL語句撤銷,將資料庫回滾到事務執行前狀態。
1、JDBC對資料庫事務處理的支持
JDBC本身就提供了對資料庫事務處理的支持,使用java.sql.Connection對象完成事務的提交。使用Connection提交資料庫事務處理代碼如下。
Connection類的setAutoCommit方法用於設置JDBC提交SQL語句的方式。設置為ture時,JDBC自動提交SQL語句,JDBC提交SQL語句的方式默認為true。設置為false時,SQL語句的提交由應用程式負責,應用程式必須調用commit方法,同時要在執行SQL語句異常處理塊中調用rollback方法,對異常發生前進行的資料庫進行回滾操作。
在企業級應用中,事務一般是並發執行的,當事務並發執行時,就會發生資料庫數據同步的問題,具體問題可分為下面四種類型。
(1)髒讀:一個資料庫事務在更新數據的過程中,數據是保存在內存中的,只有調用commit方法,更新的數據才最終寫到資料庫中。如果一個事務使用了另一個事務更新但沒保存的數據,這個數據就稱為髒數據,事務讀取這個數據就稱為髒讀。
(2)不可重複讀:在同一事務中,兩次讀取同一記錄,讀取的記錄內容卻不相同。例如,事務A第一次讀取了一條記錄,同時事務B更新並提交了該條記錄,事務A第二次讀取該條記錄時,當前讀取的記錄內容和第一次讀取的記錄內容不相同。
(3)幻讀:當事務A對表中的所有記錄進行了修改,同時事務B又在表中插入了一條新的記錄。A事務在後續對該表操作時,就會發現表中還存在沒有修改的記錄,就好象發生了幻覺一樣。
(4)丟失更新:當事務A和事務B對同一數據進行修改時,就會發生丟失更新的問題。例如,B事務對m記錄進行了修改,A事務在修改m記錄時發生異常並回滾,就會將B事務對m記錄的修改覆蓋掉。
為了解決上面提到的事務並發問題,JDBC定義了五種事務隔離級別來解決來解決這些並發導致的問題。
表1 JDBC提供的事務隔離級別說明
表中隔離級別從上到下依次增高,最高級別是TRANSACTION_SERIALIZABLE,它通過強制事務串行執行(不是並行),避免了事務並發執行導致發生的數據同步問題。出於應用程式訪問資料庫性能的考慮,一般設置隔離級別為TRANSACTION_READ_COMMITTED。
2、在Spring框架中調用事務處理
下面給出具體執行事務處理的案例程序。案例程序的數據源採用mooc資料庫,mooc資料庫的結構以及本案例中沒有列出的代碼詳見《Spring使用JDBC訪問MySQL資料庫》一文。
讓Spring框架開始執行一個資料庫事務時,需要分成三步走。第一步配置數據源DataSource;第二步聲明事務管理TransactionManager類;第三步定義可以執行事務的DAO類。
第一步:配置數據源DataSource
需要讓Spring框架知道資料庫的位置及其連接方式,這個工作由DataSource完成。Spring框架通過DataSource連接資料庫,DataSource既可以在Spring框架的配置文件中配置,也可以放在Bean類中配置。下面是在Spring配置文件中配置數據源的代碼。
配置語句定義了MySQL資料庫的URL地址、訪問帳戶及訪問密碼。
第二步:聲明事務管理TransactionManager
Spring 框架提供了PlatformTransactionManager作為事務管理類的頂層接口,聲明了初始化事務、提交事務、回滾事務等接口。接口實現由具體的資料庫驅動類實現。具體包括DataSourceTransactionManager、HibernateTransactionManager等實現類。本文主要用DataSourceTransactionManager來實現事務的管理。在Spring框架配置文件中配置DataSourceTransactionManager類。
聲明DataSourceTransactionManager類,需要傳入之前已聲明的DataSource數據源。
第三步:定義可以執行事務的DAO類
DAO提供了應用程式訪問數據源必要的接口和方法,接口和方法的具體實現細節,程序並不需要了解。DAO的具體細節詳見《Spring使用JDBC訪問MySQL資料庫》一文。
CourseTransactio類實現了CourseDao接口,CourseDao是訪問mooc資料庫的頂層接口,接口提供了mooc資料庫表的增刪改查操作。CourseTransactio主要實現了CourseDao類的buyCourse,實現學生購買課程事務。購買課程事務涉及到更新teacher表,在student_course表增加一條購買記錄,更新student表的餘額欄位資料庫操作,這些操作需要進行連續處理,中間不能中斷出錯,如果出錯則需要做回滾處理。 因此,buyCourse方法採用資料庫事務進行處理。
事務處理從TransactionDefinition開始,前面我們談到了事務的隔離級別,TransactionDefinition就是用來定義事務隔離級別的。DefaultTransactionDefinition表示使用資料庫的默認隔離級別,對大部分資料庫而言,默認隔離級別是TRANSACTION_READ_COMMITTED。
當TransactionDefinition 創建後,可以通過調用 getTransaction方法開始事務,該方法會返回 TransactionStatus 的一個實例。 TransactionStatus 用於追蹤當前的事務狀態,如果後面的SQL語句都運行成功,可以使用 TransactionManager 的 commit() 方法來提交這個事務,否則使用 rollback() 方法來回滾整個操作。
完整的配置文件代碼。
學生實體類代碼。
老師實體類代碼。
student表映射到學生實體類。
teacher表映射到老師實體類。
測試類代碼。
課程小結
(1)事務處理對資料庫來說,是對資料庫的一系列SQL語句操作,這些操作被組織為一個事務。事務具有原子性,即事物中的操作要麼全部執行,要麼全部不執行。若事務中的SQL語句在執行過程中發生錯誤時,事務需要對已經執行的SQL語句進行回滾操作,撤銷先前對資料庫的操作,防止資料庫出現錯誤狀態。
(2)讓Spring框架開始執行一個資料庫事務時,需要分成三步走。第一步配置數據源DataSource;第二步聲明事務管理TransactionManager類;第三步定義可以執行事務的DAO類。