事務用于在并發訪問期間提供數據完整性,正確的應用程序語義和一致的數據視圖。 需要所有JDBC兼容驅動程序來提供事務支持。 JDBC API中的事務管理反映了SQL:2003規范,并包含了這些概念
- 自動提交模式
- 事務隔離級別
- 保存點
本章介紹與單個Connection對象關聯的事務語義。 涉及多個Connection對象的事務在第12章“分布式事務”中討論。
10.1 交易界限和自動提交
什么時候開始一個新的事務是由JDBC驅動程序或底層數據源隱含的決定,雖然一些數據源實現了一個明確的“begin transaction”語句,但是沒有JDBC API可以實現,通常,當當前的SQL語句需要一個并且沒有事務已經存在的時候,一個新的事務被啟動。 一個給定的SQL語句是否需要一個事務也由SQL:2003指定。
Connection屬性auto-commit指定何時結束事務。 一旦該語句完成,啟用自動提交會在每個單獨的SQL語句之后導致事務提交。 一個語句被認為是“完成”的點取決于SQL語句的類型以及應用程序在執行它之后執行的操作:
- 對于“數據操作語言”(DML)語句(如“插入”,“更新”,“刪除”和“DDL”語句),語句在執行完畢后立即完成
- 對于Select語句,當關聯的結果集關閉時,該語句將完成。
- 對于CallableStatement對象或返回多個結果的語句,當所有關聯的結果集都已關閉時,該語句已完成,并且已檢索所有更新計數和輸出參數
10.2 禁用自動提交模式
當禁用自動提交時,每個事務必須通過調用Connection方法提交或通過調用Connection方法回滾來顯式回滾來顯式提交。 這適用于在驅動程序上方的層中進行事務管理的情況,例如
- 當應用程序需要將多個SQL語句組合成一個事務
- 當事務由應用程序服務器管理時
默認值是在創建Connection對象時啟用自動提交模式。 如果自動提交的值在事務中間更改,則提交當前事務。 如果調用了setAutoCommit,并且auto-commit的值不會從當前值更改,則被視為無操作
如第12章“分布式事務”所述,為參與分布式事務的連接啟用自動提交是一個錯誤。
10.2 事務隔離等級
事務隔離級別指定事務中的語句“可見”哪些數據。 它們通過定義在相同目標數據源之間的交易之間可以進行什么交互(如果有的話)直接影響并發訪問級別。 并發事務之間的可能交互分類如下:
當允許事務查看未提交的數據更改時,會發生臟讀。 換句話說,交易之前所做的更改在提交之前在事務外部可見。 如果更改回滾而不是提交,則可以根據不正確的臨時數據完成其他事務的工作。
不可重復讀取時發生:
1.事務A讀取一行
2.事務B更改行
3,事務A第二次讀取相同的行并獲得不同的結果幻象讀取發生時
1.事務A讀取滿足WHERE條件的所有行
2.事務B插入一個滿足相同條件的附加行
3.事務A重新評估WHERE條件并拾取附加的“幻像”行
JDBC通過添加TRANSACTION_NONE來增強 SQL:2003定義的四個級別的事務隔離。 從最少限制到最嚴格的交易隔離級別是:
1,TRANSACTION_NONE :表示驅動程序不支持事務,這意味著它不是JDBC兼容的驅動程序。
2,TRANSACTION_READ_UNCOMMITTED:允許事務查看未提交的數據更改。 這意味著臟的讀取,不可重復的讀取和幻像讀取是可能的
3,TRANSACTION_READ_COMMITTED:意味著事務之前進行的任何更改在事務發生之前都不可見,直到事務被提交。 這樣可以防止臟讀,但是不可重復的讀取和幻像讀取仍然是可能的。
4,TRANSACTION_REPEATABLE_READ:不允許臟讀和不可重讀讀。 幻影讀取仍然是可能的。
5,TRANSACTION_SERIALIZABLE:指定防止臟讀,不可重復讀取和幻像讀取。
10.2.1 使用 setTransactionIsolation 方法
Connection對象的默認事務級別由提供連接的驅動程序決定。 通常,它是底層數據源支持的默認事務級別
提供了Connection方法setTransactionIsolation,以允許JDBC客戶端更改給定Connection對象的事務隔離級別。 新的隔離級別對于會話的剩余部分或直到下一次調用setTransactionIsolation方法仍然有效
在事務中間調用setTransactionIsolation方法的結果是實現定義的
方法getTransactionIsolation的返回值應該反映實際發生時隔離級別的變化。 建議驅動程序實現setTransactionIsolation方法來更改從下一個事務開始的隔離級別。 提交當前事務以使效果立即也是有效的實現
給定的JDBC驅動程序可能不支持所有四個事務隔離級別(不計算TRANSACTION_NONE)。 如果驅動程序不支持在調用setTransactionIsolation中指定的隔離級別,則可以替換更高級別,更嚴格的事務隔離級別。 如果驅動程序無法替代較高的事務級別,則會引發SQLException。 DatabaseMetaData方法supportsTransactionIsolationLevel可以用于確定驅動程序是否支持給定的級別
10.2.2 性能注意事項
隨著事務隔離級別的增加,需要更多的鎖定和其他DBMS開銷來確保正確的語義。 這反過來降低了可以支持的并發訪問的程度。 因此,當應用程序使用更高的事務隔離級別時,應用程序可能會看到降低的性能。 因此,無論是應用程序本身還是應用程序服務器的一部分,事務管理器在確定哪個事務隔離級別合適時,應該對數據一致性的需求與性能要求進行權衡。
10.3 Savepoints
保存點通過標記事務中的中間點來提供對事務的更細粒度的控制。 一旦設置了保存點,事務可以回滾到該保存點,而不影響以前的工作
DatabaseMetaData.supportsSavepoints方法可用于確定JDBC驅動程序和DBMS是否支持保存點
10.3.1 設置和回滾至 保存點
Connection.setSavepoint方法可用于在當前事務中設置保存點。 如果調用了setSavePoint并且沒有活動的事務,則事務將被啟動。 Connection.rollback方法已被重載以獲取一個保存點參數
代碼示例10-2將一行插入到表中,設置保存點svpt1,然后插入第二行。 當事務稍后回滾到svpt1時,第二個插入被撤消,但是第一個插入保持不變。 換句話說,當交易被提交時,只有包含“FIRST”的行將被添加到TAB1
conn.createStatement();
int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " +
"(’FIRST’)");
// set savepoint
Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1");
rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) " +
"VALUES (’SECOND’)");
...
conn.rollback(svpt1);
...
conn.commit();
10.3.4 釋放保存點
Connection.releaseSavepoint方法將Savepoint對象作為參數,并從當前事務中刪除它和任何后續的保存點。
一旦保存點被釋放,嘗試在回滾操作中引用它將導致拋出SQLException。
在事務中創建的任何保存點將自動釋放,并在事務提交或整個事務回滾時變為無效。
將事務回滾到保存點將自動釋放并使無效的所有保存點之后創建的任何其他保存點無效