官术网_书友最值得收藏!

5.4 事務管理

事務用來提供數據集成性、正確的應用語義以及并發訪問時數據的一致性視圖。所有符合JDBC規范的驅動都必須支持事務,JDBC的事務管理API參照SQL:2003標準并且包含以下概念:

  • 自動提交模式。
  • 事務隔離級別。
  • 保存點(Savepoint)。

5.4.1 事務邊界和自動提交

什么時候應該開啟一個事務是JDBC驅動或者底層的數據源做的一個隱式的決定,盡管有一些數據源支持begin transaction語句,但這個語句沒有對應的JDBC API。如果一條SQL語句要求開啟一個事務并且當前沒有事務未執行完,那么新事務就會被開啟。

Connection有一個屬性autocommit來表明什么時候應該結束事務。如果autocommit啟用,那么每一條SQL語句完全執行后都會自動執行事務的提交。以下幾種情況視為完全執行:

  • DML語句(例如Insert、Update、Delete)和DDL語句在數據源端執行完畢就代表語句完全執行。
  • 對于Select語句來說,完全執行意味著對應的結果集被關閉。
  • 對于CallableStatement對象或者那些返回多個結果集的語句,完全執行意味著所有的結果集都關閉,以及所有的影響行數和出參都被獲取到了。

5.4.2 關閉自動提交模式

以下代碼示范了如何關閉自動提交模式:

    // Assume con is a Connection object
    con.setAutoCommit(false);

當關閉自動提交時,必須顯式地調用Connection的commit方法提交事務或者調用rollback方法回滾事務。這種處理方式是合理的,因為事務的管理工作不是驅動應該做的,應用層應該自己管理事務,例如:

  • 當應用需要將一組SQL組成一個事務的時候。
  • 當應用服務器管理事務的時候。

autocommit的默認值為true,如果在一個事務中autocommit的值被改變了,那么將會導致當前事務被提交。如果調用了setAutocommit方法,但沒有改變原來的值,就不會產生其他附加影響,相當于沒有調過一樣。

如果一條連接參加了分布式事務,那么autocommit不能設置為true。

5.4.3 事務隔離級別

事務隔離級別定義在一個事務中哪些數據是對當前執行的語句“可見”的。在并發訪問數據庫時,事務隔離級別定義了多個事務之間對于同一個目標數據源訪問時的可交叉程度。可交叉程度可分為以下幾類:

  • dirty read(臟讀):當一個事務能看見另一個事務未提交的數據時,就稱為臟讀,換言之,一個事務修改數據后,在未提交之前,就能被其他事務看見,如果這個事務被回滾了,而不是提交了,那么其他事務看到的數據是不正確的,是“臟”的。
  • nonrepeatable read(不可重復讀):假設事務A讀取了一行數據,接下來事務B改變了這行數據,之后事務A再一次讀取這行數據,這時候事務A就取到了兩個不同的結果。
  • phantom read(幻讀):假設事務A通過一個where條件讀取到了一個結果集,事務B這時插入了一條符合事務A的where條件的數據,之后事務A通過同樣的where條件再次進行查詢時會發現多出來一條數據。

JDBC規范增加了TRANSACTION_NONE隔離級別,滿足了SQL:2003定義的4種事務隔離級別。隔離級別從最寬松到最嚴格,排序如下:

  • TRANSACTION_NONE:這意味著當前的JDBC驅動不支持事務,也意味著這個驅動不符合JDBC規范。
  • TRANSACTION_READ_UNCOMMITTED:允許事務看到其他事務修改了但未提交的數據,這意味著有可能是臟讀、不可重復讀或者幻讀。
  • TRANSACTION_READ_COMMITTED:一個事務在未提交之前,所做的修改不會被其他事務看見。這能避免臟讀,但避免不了不可重復讀和幻讀。
  • TRANSACTION_REPEATABLE_READ:避免了臟讀和不可重復讀,但幻讀依然是有可能發生的。
  • TRANSACTION_SERIALIZABLE:避免了臟讀、不可重復讀以及幻讀。

一條連接的默認事務隔離級別是由驅動決定的,這個隔離級別往往是底層的數據源默認的事務隔離級別。應用程序可以使用Connection類里的setTransactionIsolation方法來改變一條連接的事務隔離級別。在一個事務中調用setTransactionIsolation方法會有什么樣的結果完全由驅動的實現決定。

可能有些驅動實現并不支持所有的4種事務隔離級別,如果通過setTransactionIsolation方法設置的隔離級別驅動不支持的話,驅動就可以主動將事務隔離級別設置為更高、更嚴格的事務隔離級別,如果沒法設置為更高或者更嚴格的事務隔離級別,驅動就應該拋出SQLException。可以使用DatabaseMetaData的supportsTransactionIsolationLevel方法來判斷驅動是否支持某個事務隔離級別。

5.4.4 性能考慮

事務隔離級別設置得越高,為了保證事務的正確語義,意味著會有更多的鎖等待、鎖競爭以及DBMS的附加損耗。這反過來也會降低并發訪問性,所以應用程序可能會發現事務隔離級別越高,性能反而會下降。為此,事務的管理者應該權衡兩者的利弊,設置合理的事務隔離級別。

5.4.5 保存點

我們可以在一個事務的中間設置一個保存點來更靈活地控制事務。一旦事務設置了一個保存點,事務就可以回滾到這個保存點,不會影響保存點之前的操作。可以使用DatabaseMetaData.supportsSavepoints方法來判斷驅動或者數據庫是否支持這個功能。

1.設置保存點

Connection.setSavepoint方法可以用來在當前事務中設置一個保存點,如果當前方法沒有在事務中,則調用這個方法能開啟一個事務。Connection.rollback方法有一個重載版本,能夠接收一個保存點作為參數。

上面的代碼實例中,插入一行數據后,保存一個保存點,再插入一行數據。當事務被回滾到保存點的時候,第二行數據不會被插入,第一行數據依然會被插入。當連接提交后,第一行數據將會保存在表里。

2.釋放保存點

Connection.releaseSavepoint方法接收一個保存點作為參數,刪除這個保存點以及在它之后的保存點。如果一個保存點已經被釋放了,還把它作為rollback的參數,就會導致SQLException。當事務提交或者完全回滾的時候,所有的保存點都會被自動釋放。當回滾到某個保存點后,這個保存點以及在它之后定義的保存點都會被自動釋放掉。

主站蜘蛛池模板: 都江堰市| 阿巴嘎旗| 枣强县| 原平市| 北票市| 泾川县| 湾仔区| 米脂县| 乐都县| 崇信县| 鲁山县| 忻城县| 高密市| 淮南市| 鄂伦春自治旗| 库尔勒市| 都江堰市| 沁源县| 安塞县| 全州县| 乃东县| 安阳县| 得荣县| 鞍山市| 古蔺县| 吴旗县| 乐东| 分宜县| 神木县| 班戈县| 固安县| 绥滨县| 兴宁市| 永靖县| 阿巴嘎旗| 大宁县| 准格尔旗| 台州市| 上高县| 秭归县| 磐石市|