一、什麼是JAVA事務
通常的觀念認為,事務僅與數據庫相關。
事務必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性 (isolation)和持久性(durability)的縮寫。事務的原子性表示事務執行過程中的任何失敗都將導致事務所做的任何修改失效。一致性表示 當事務執行失敗時,所有被該事務影響的數據都應該恢復到事務執行前的狀態。隔離性表示在事務執行過程中對數據的修改,在事務提交之前對其他事務不可見。持 久性表示已提交的數據在事務執行失敗時,數據的狀態都應該正確。
通俗的理解,事務是一組原子操作單元,從數據庫角度說,就是一組SQL指令,要麼全部執行成功,若因為某個原因其中一條指令執行有錯誤,則撤銷先前執行過的所有指令。更簡答的說就是:要麼全部執行成功,要麼撤銷不執行。
既然事務的概念從數據庫而來,那Java事務是什麼?之間有什麼聯系?
實際上,一個Java應用系統,如果要操作數據庫,則通過JDBC來實現的。增加、修改、刪除都是通過相應方法間接來實現的,事務的控制也相應轉移到Java程序代碼中。因此,數據庫操作的事務習慣上就稱為Java事務。
二、為什麼需要Java事務
事務是為解決數據安全操作提出的,事務控制實際上就是控制數據的安全訪問。舉一個簡單例子:比如銀行轉帳業務,賬戶A要將自己賬戶上的1000元轉到B賬 戶下面,A賬戶余額首先要減去1000元,然後B賬戶要增加1000元。假如在中間網絡出現了問題,A賬戶減去1000元已經結束,B因為網絡中斷而操作 失敗,那麼整個業務失敗,必須做出控制,要求A賬戶轉帳業務撤銷。這才能保證業務的正確性,完成這個操作就需要事務,將A賬戶資金減少和B賬戶資金增加方 到一個事務裡面,要麼全部執行成功,要麼操作全部撤銷,這樣就保持了數據的安全性。
三、Java事務的類型
Java事務的類型有三種:JDBC事務、JTA(Java Transaction API)事務、容器事務。
1、JDBC事務
JDBC 事務是用 Connection 對象控制的。JDBC Connection 接口( java.sql.Connection )提供了兩種事務模式:自動提交和手工提交。 java.sql.Connection 提供了以下控制事務的方法:
public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
使用 JDBC 事務界定時,您可以將多個 SQL 語句結合到一個事務中。JDBC 事務的一個缺點是事務的范圍局限於一個數據庫連接。一個 JDBC 事務不能跨越多個數據庫。
2、JTA(Java Transaction API)事務
JTA是一種高層的,與實現無關的,與協議無關的API,應用程序和應用服務器可以使用JTA來訪問事務。
JTA允許應用程序執行分布式事務處理——在兩個或多個網絡計算機資源上訪問並且更新數據,這些數據可以分布在多個數據庫上。JDBC驅動程序的JTA支持極大地增強了數據訪問能力。
如果計劃用 JTA 界定事務,那麼就需要有一個實現 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驅動程序。一個實現了這些接口的驅動程序將可以參與 JTA 事務。一個 XADataSource 對象就是一個 XAConnection 對象的工廠。 XAConnection s 是參與 JTA 事務的 JDBC 連接。
您將需要用應用服務器的管理工具設置 XADataSource .從應用服務器和 JDBC 驅動程序的文檔中可以了解到相關的指導。
J2EE應用程序用 JNDI 查詢數據源。一旦應用程序找到了數據源對象,它就調用 javax.sql.DataSource.getConnection() 以獲得到數據庫的連接。
XA 連接與非 XA 連接不同。一定要記住 XA 連接參與了 JTA 事務。這意味著 XA 連接不支持 JDBC 的自動提交功能。同時,應用程序一定不要對 XA 連接調用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() .
相反,應用程序應該使用 UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() .
3、容器事務
容器事務主要是J2EE應用服務器提供的,容器事務大多是基於JTA完成,這是一個基於JNDI的,相當復雜的API實現。相對編碼實現JTA事務管理, 我們可以通過EJB容器提供的容器事務管理機制(CMT)完成同一個功能,這項功能由J2EE應用服務器提供。這使得我們可以簡單的指定將哪個方法加入事 務,一旦指定,容器將負責事務管理任務。這是我們土建的解決方式,因為通過這種方式我們可以將事務代碼排除在邏輯編碼之外,同時將所有困難交給J2EE容 器去解決。使用EJB CMT的另外一個好處就是程序員無需關心JTA API的編碼,不過,理論上我們必須使用EJB.
四、三種Java事務差異
1、JDBC事務控制的局限性在一個數據庫連接內,但是其使用簡單。
2、JTA事務的功能強大,事務可以跨越多個數據庫或多個DAO,使用也比較復雜。
3、容器事務,主要指的是J2EE應用服務器提供的事務管理,局限於EJB應用使用。
五、總結
Java事務控制是構建J2EE應用不可缺少的一部分,合理選擇應用何種事務對整個應用系統來說至關重要。一般說來,在單個JDBC 連接連接的情況下可以選擇JDBC事務,在跨多個連接或者數據庫情況下,需要選擇使用JTA事務,如果用到了EJB,則可以考慮使用EJB容器事務
事務的特性:
1) 原子性(atomicity):事務是數據庫的邏輯工作單位,而且是必須是原子工作單位,對於其數據修改,要麼全部執行,要麼全部不執行。
2) 一致性(consistency):事務在完成時,必須是所有的數據都保持一致狀態。在相關數據庫中,所有規則都必須應用於事務的修改,以保持所有數據的完整性。
3) 隔離性(isolation):一個事務的執行不能被其他事務所影響。
4) 持久性(durability):一個事務一旦提交,事物的操作便永久性的保存在DB中。即使此時再執行回滾操作也不能撤消所做的更改。
事務(Transaction):是並發控制的單元,是用戶定義的一個操作序列。這些操作要麼都做,要麼都不做,是一個不可分割的工作單位。通過事務,sql server 能將邏輯相關的一組操作綁定在一起,以便服務器 保持數據的完整性。事務通常是以begin transaction開始,以commit或rollback結束。Commint表示提交,即提交事務的所有操作。具體地說就是將事務中所有對數據的更新寫回到磁盤上的物理數據庫中去,事務正常結束。Rollback表示回滾,即在事務運行的過程中發生了某種故障,事務不能繼續進行,系統將事務中對數據庫的所有已完成的操作全部撤消,滾回到事務開始的狀態。
自動提交事務:每條單獨的語句都是一個事務。每個語句後都隱含一個commit。 (默認)
顯式事務:以begin transaction顯示開始,以commit或rollback結束。
隱式事務:當連接以隱式事務模式進行操作時,sql server數據庫引擎實例將在提交或回滾當前事務後自動啟動新事務。無須描述事物的開始,只需提交或回滾每個事務。但每個事務仍以commit或rollback顯式結束。連接將隱性事務模式設置為打開之後,當數據庫引擎實例首次執行下列任何語句時,都會自動啟動一個隱式事務:alter table,insert,create,open ,delete,revoke ,drop,select, fetch ,truncate table,grant,update在發出commit或rollback語句之前,該事務將一直保持有效。在第一個事務被提交或回滾之後,下次當連接執行以上任何語句時,數據庫引擎實例都將自動啟動一個新事務。該實例將不斷地生成隱性事務鏈,直到隱性事務模式關閉為止。
Java JDBC事務機制
首先,我們來看看現有JDBC操作會給我們打來什麼重大問題,比如有一個業務:當我們修改一個信息後再去查詢這個信息,看是這是一個簡單的業務,實現起來也非常容易,但當這個業務放在多線程高並發的平台下,問題自然就出現了,比如當我們執行了一個修改後,在執行查詢之前有一個線程也執行了修改語句,這是我們再執行查詢,看到的信息就有可能與我們修改的不同,為了解決這一問題,我們必須引入JDBC事務機制,其實代碼實現上很簡單,一下給出一個原理實現例子供大家參考:
private Connection conn = null;
private PreparedStatement ps = null;
try {
conn.setAutoCommit(false); //將自動提交設置為false
ps.executeUpdate("修改SQL"); //執行修改操作
ps.executeQuery("查詢SQL"); //執行查詢操作
conn.commit(); //當兩個操作成功後手動提交
} catch (Exception e) {
conn.rollback(); //一旦其中一個操作出錯都將回滾,使兩個操作都不成功
e.printStackTrace();
}
與事務相關的理論
1.事務(Transaction)的四個屬性(ACID)
原子性(Atomic) 對數據的修改要麼全部執行,要麼全部不執行。
一致性(Consistent) 在事務執行前後,數據狀態保持一致性。
隔離性(Isolated) 一個事務的處理不能影響另一個事務的處理。
持續性(Durable) 事務處理結束,其效果在數據庫中持久化。
2.事務並發處理可能引起的問題
髒讀(dirty read) 一個事務讀取了另一個事務尚未提交的數據,
不可重復讀(non-repeatable read) 一個事務的操作導致另一個事務前後兩次讀取到不同的數據
幻讀(phantom read) 一個事務的操作導致另一個事務前後兩次查詢的結果數據量不同。
舉例:
事務A、B並發執行時,
當A事務update後,B事務select讀取到A尚未提交的數據,此時A事務rollback,則B讀到的數據是無效的"髒"數據。
當B事務select讀取數據後,A事務update操作更改B事務select到的數據,此時B事務再次讀去該數據,發現前後兩次的數據不一樣。
當B事務select讀取數據後,A事務insert或delete了一條滿足A事務的select條件的記錄,此時B事務再次select,發現查詢到前次不存在的記錄("幻影"),或者前次的某個記錄不見了。
JDBC的事務支持
JDBC對事務的支持體現在三個方面:
1.自動提交模式(Auto-commit mode)
Connection提供了一個auto-commit的屬性來指定事務何時結束。
a.當auto-commit為true時,當每個獨立SQL操作的執行完畢,事務立即自動提交,也就是說每個SQL操作都是一個事務。
一個獨立SQL操作什麼時候算執行完畢,JDBC規范是這樣規定的:
對數據操作語言(DML,如insert,update,delete)和數據定義語言(如create,drop),語句一執行完就視為執行完畢。
對select語句,當與它關聯的ResultSet對象關閉時,視為執行完畢。
對存儲過程或其他返回多個結果的語句,當與它關聯的所有ResultSet對象全部關閉,所有update count(update,delete等語句操作影響的行數)和output parameter(存儲過程的輸出參數)都已經獲取之後,視為執行完畢。
b. 當auto-commit為false時,每個事務都必須顯示調用commit方法進行提交,或者顯示調用rollback方法進行回滾。auto-commit默認為true。
JDBC提供了5種不同的事務隔離級別,在Connection中進行了定義。
2.事務隔離級別(Transaction Isolation Levels)
JDBC定義了五種事務隔離級別:
TRANSACTION_NONE JDBC驅動不支持事務
TRANSACTION_READ_UNCOMMITTED 允許髒讀、不可重復讀和幻讀。
TRANSACTION_READ_COMMITTED 禁止髒讀,但允許不可重復讀和幻讀。
TRANSACTION_REPEATABLE_READ 禁止髒讀和不可重復讀,單運行幻讀。
TRANSACTION_SERIALIZABLE 禁止髒讀、不可重復讀和幻讀。
3.保存點(SavePoint)
JDBC定義了SavePoint接口,提供在一個更細粒度的事務控制機制。當設置了一個保存點後,可以rollback到該保存點處的狀態,而不是rollback整個事務。
Connection接口的setSavepoint和releaseSavepoint方法可以設置和釋放保存點。
JDBC規范雖然定義了事務的以上支持行為,但是各個JDBC驅動,數據庫廠商對事務的支持程度可能各不相同。如果在程序中任意設置,可能得不到想要的效果。為此,JDBC提供了DatabaseMetaData接口,提供了一系列JDBC特性支持情況的獲取方法。比如,通過DatabaseMetaData.supportsTransactionIsolationLevel方法可以判斷對事務隔離級別的支持情況,通過DatabaseMetaData.supportsSavepoints方法可以判斷對保存點的支持情況。