事務用來提供數據集成性、正確的應用語義,以及併發訪問時數據的一致性視圖。全部符合 JDBC 規範的驅動都必須支持事務,JDBC 的事務管理 API 參照 SQL:2003 標準而且包含了如下的概念:數據庫
本章討論單個鏈接上的事務,涉及多條鏈接的事務將會在第十二章《分佈式事務》中討論。服務器
何時應該開啓一個事務,是 JDBC 驅動或者底層的數據源作的一個隱式的決定,儘管有一些數據源支持 begin transaction 語句,但這個語句沒有對應的 JDBC API。當一條 SQL 語句要求開啓一個事務而且當前沒有事務未執行完,那麼新事務就會被開啓。
Connection 有一個屬性 autocommit 來代表何時應該結束事務。若是 autocommit 啓用,那麼每一條 SQL 語句徹底執行後,都會自動執行事務的提交。如下幾種狀況,視爲徹底執行:微信
如下代碼示範瞭如何關閉自動提交模式:併發
// Assume con is a Connection object con.setAutoCommit(false);
當關閉自動提交,必須顯式地調用 Connection 的 commit 方法提交事務或者調用 rollback 方法回滾事務。這種處理方式是合理的,由於事務的管理工做不是驅動應該作的,應用層應該本身管理事務,例如:分佈式
autocommit 的默認值爲 true,若是在一個事務的過程當中,autocommit 的值被改變了,那麼將會致使當前事務被提交。若是調用了 setAutocommit 方法,但沒有改變原來的值,則不會產生其它附加影響,至關於沒有調過同樣。性能
若是一條鏈接參加了分佈式事務,那 autocommit 不能設置爲 true。第12章將會介紹到。spa
事務隔離級別定義了在一個事務中,哪些數據是對當前執行的語句「可見」的。在併發訪問數據庫時,事務隔離級別定義了多個事務之間對於同個目標數據源訪問時的可交叉程度。可交叉程度可分爲如下幾類:code
當一個事務能看見另一個事務未提交的數據時,就稱爲髒讀,換言之,一個事務修改數據後再未提交以前,就能被其它事務看見,若是這個事務被回滾了而不是提交了,那麼其它事務看到的數據則是不正確的,是「髒」的。對象
假設事務 A 讀取了一行數據,接下來事務 B 改變了這行數據,以後事務 A 又再一次讀取這行數據,這時候事務 A 就取到了兩個不一樣的結果。排序
假設事務 A 經過一個 where 條件讀取到了一個結果集,事務 B 這時插入了一條符合事務 A 的 where 條件的數據,以後事務 A 經過一樣的 where 條件再次進行查詢時,發現了多出來一條數據。
JDBC 規範增長了 TRANSACTION_NONE 隔離級別,來知足了 SQL:2003 定義的 4 種事務隔離級別。隔離級別從最寬鬆到最嚴格,排序以下所示:
這意味着當前的 JDBC 驅動不支持事務,也意味着這個驅動不符合 JDBC 規範。
容許事務看到其它事務修改了但未提交的數據,這意味着有多是髒讀、先後不一致讀或者幻讀。
一個事務在未提交以前,所作的修改不會被其它事務所看見。這能避免髒讀,但避免不了先後不一致讀和幻讀。
避免了髒讀和先後不一致讀,但幻讀依然是有可能發生的
避免了髒讀、先後不一致讀以及幻讀
一條鏈接的默認事務隔離級別是由驅動決定的,這個隔離級別也每每是底層的數據源默認的事務隔離級別。
應用程序可使用 Connection 類裏的 setTransactionIsolation 方法來改變一條鏈接的事務隔離級別。若是在一個事務的過程當中調用 setTransactionIsolation 方法,會有什麼樣結果,徹底由驅動的實現決定。
getTransactionIsolation 方法的返回值應當能正確地反映當前鏈接的事務隔離級別,建議實現驅動的時候要實現 setTransactionIsolation 方法,能夠在一個事務開啓以前去設置事務隔離級別。此外,調用
setTransactionIsolation 這個方法時,自動提交當前事務,也是一種合理的 setTransactionIsolation 實現。
可能有些驅動實現並不支持全部的四種事務隔離級別,若是經過 setTransactionIsolation 方法設置的隔離級別驅動不支持的話,驅動能夠主動將事務隔離級別設置爲更高更嚴格的事務隔離級別,若是無法設置爲更高或者更嚴格的,驅動應該拋出 SQLException。可使用 DatabaseMetaData 的 supportsTransactionIsolationLevel 方法來判斷驅動是否支持某個事務隔離級別。
事務隔離級別設置得越高,爲了保證事務的正確語義,意味着會有更多的鎖等待、鎖競爭以及 DBMS 的附加損耗。這反過來也會下降併發訪問性,因此應用程序可能會發現事務隔離級別越高時,性能反而會降低。爲此,事務的管理者應該權衡二者的利弊,設置合理的事務隔離級別。
savepoints 能夠在一個事務的中間設置一個標記點,來更靈活地控制事務。一旦事務設置了一個標記點,事務能夠回滾到這個標記點,不會影響標記點以前的操做。可使用 DatabaseMetaData.supportsSavepoints 方法來判斷驅動或者數據庫是否支持這個功能。
Connection.setSavepoint 方法能夠用來在當前事務中設置一個標記點,同時若是當前沒有在事務中,調用這個方法能開啓一個事務。 Connection.rollback 方法有一個重載版本,可以接收一個 savepoint 做爲參數。
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();
上面的代碼實例中,插入一行數據後,保存一個標記點,而後插入一行數據。當事務被回滾到標記點的時候,第二行數據不會被插入,第一行數據依然會被插入。當鏈接提交後,第一行數據將會保存在表裏。
Connection.releaseSavepoint 方法接收一個 Savepoint 做爲參數,刪除這個標點以及在它以後的標記點。若是一個 savepoint 已經被釋放了,還把它做爲 rollback 的參數的話,將會致使 SQLException。當事務提交或者徹底回滾的時候,全部的 savepoints 都會被自動釋放。當回滾到某個 savepoint 後,這個 savepoint 以及在它以後定義的 savepoint 都會被自動釋放掉。