深入解析Java中的JDBC事務(wù)
事務(wù)
事務(wù)是一步或多步組成操作序列組成的邏輯執(zhí)行單元,這個序列要么全部執(zhí)行,要么則全部放棄執(zhí)行。事務(wù)的四個特性:原子性(Atomicity)、一致性(Consistency)、隔離性(IsoIation)和持續(xù)性(Durability)原子性(Atomicity):事務(wù)應(yīng)用最小的執(zhí)行單元,不可再分。是事務(wù)中不可再分的最小邏輯執(zhí)行體。
一致性(Consistency):事務(wù)的執(zhí)行結(jié)果,必須使數(shù)據(jù)庫的從一個一致性的狀態(tài)變到另一個一致性的狀態(tài)。
隔離線(IsoIation):各個事務(wù)的執(zhí)行互不干擾,任意一個事務(wù)的內(nèi)部操作對其他并發(fā)的事務(wù),都是隔離的。也就是:并發(fā)執(zhí)行的事務(wù)之間不能看到對方的中間狀態(tài),并發(fā)執(zhí)行的事務(wù)之間不能互相影響。
持續(xù)性(Durability):持續(xù)性也稱為持久性(Persistence),指事務(wù)一旦提交,對數(shù)據(jù)所做的任何改變,都要記錄到永久存儲器中,通常就是保存在物理數(shù)據(jù)庫中。
通常數(shù)據(jù)庫的事務(wù)涉及到的語句有:一組DML(Data Munipulation Language,數(shù)據(jù)操作語言)語句,這組DML語句修改后數(shù)據(jù)將保持較好的一致性; 操作表的語句,如插入、修改、刪除等;一個DDL(Data Definition Language,數(shù)據(jù)定義語言)語句,操作數(shù)據(jù)對象的語言,有create、alter、drop。一個DCL(Data Control Language,數(shù)據(jù)控制語言)語句,主要有g(shù)rant、revoke語句。 DDL和DCL語句最多只能有一個,因為它們都會導(dǎo)致事務(wù)的立即提交。當(dāng)事務(wù)所包含的全部數(shù)據(jù)庫操作都成功執(zhí)行后,應(yīng)該提交事務(wù),使這些修改永久生效。事務(wù)提交有兩種方式:顯示提交和自動提交。顯示提交:使用commit提交自動提交:執(zhí)行DLL或DCL,或者程序正常退出 當(dāng)事務(wù)包含的任意一個數(shù)據(jù)庫操作執(zhí)行失敗后,應(yīng)該回滾(rollback)事務(wù),使該事務(wù)中所作的修改全部失效。事務(wù)的回滾方式有兩種:顯示回滾和自動回滾。顯示回滾:使用rollback自動回滾:系統(tǒng)錯誤或強行退出。
事務(wù)并發(fā)處理可能的問題
1、臟讀(dirty read):一個事務(wù)讀取了另一個事務(wù)尚未提交的數(shù)據(jù)
2、不可重復(fù)讀(non-repeatable read):一個事務(wù)的操作導(dǎo)致另一個事務(wù)前后兩次讀到不同的數(shù)據(jù)
3、幻讀(phantom read):一個事務(wù)的操作導(dǎo)致另一個事務(wù)前后兩次查詢的結(jié)果數(shù)據(jù)量不同
舉例:
事務(wù)A、B并發(fā)執(zhí)行時:
- 當(dāng)A事務(wù)update后,B事務(wù)select讀取到A尚未提交的數(shù)據(jù),此時A事務(wù)rollback,則B讀到的數(shù)據(jù)是無效的臟數(shù)據(jù)
- 當(dāng)B事務(wù)select讀取數(shù)據(jù)后,A事務(wù)update操作更改B事務(wù)select到的數(shù)據(jù),此時B事務(wù)再次讀取該數(shù)據(jù),發(fā)現(xiàn)前后兩次的數(shù)據(jù)不一樣
- 當(dāng)B事務(wù)select讀取數(shù)據(jù)后,A事務(wù)insert或delete了一條滿足A事務(wù)的select條件的記錄,此時B事務(wù)再次select,發(fā)現(xiàn)查詢到前次不存在的記錄,或者前次的某個記錄不見了
Java JDBC事務(wù)機制
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class JDBCTransaction { public static final String URL = "com.mysql.jdbc.Driver"; public static final String USER = "root"; public static final String PASSWD = "123456"; public static void jdbcTransaction(int id) { Connection conn = null; PreparedStatement pstmtupdate = null; PreparedStatement pstmtquery = null; String updatesql = "更新sql"; String querysql = "查詢sql"; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(URL, USER, PASSWD); conn.setAutoCommit(false); // 自動提交設(shè)置為false // 執(zhí)行更新操作 pstmtupdate = conn.prepareStatement(updatesql); pstmtupdate.executeUpdate(); // 執(zhí)行查找操作 pstmtquery = conn.prepareStatement(querysql); pstmtquery.executeQuery(); conn.commit(); conn.setAutoCommit(true); pstmtupdate.close(); pstmtquery.close(); conn.close(); } catch (Exception e) { try { conn.rollback(); } catch (SQLException e1) {} e.printStackTrace(); } finally { try { if (pstmtupdate != null) { pstmtupdate.close(); } if (pstmtquery != null) { pstmtquery.close(); } if (conn != null) { conn.close(); } } catch (SQLException e2) {} } } }
JDBC的事務(wù)支持
JDBC的Connection也支持事物,Connection默認打開自動提交,即關(guān)閉事物。也就是說,每條SQL語句執(zhí)行就會立即提交到數(shù)據(jù)庫,永久生效,無法對其進行操作。關(guān)閉Connection的自動提交,開啟事物。Connection的setAutoCommit方法即可:connection.setAutoCommit(false);通過connection.getAutoCommit()來獲取事物的模式。當(dāng)我們開啟事物后,在當(dāng)前Connection中完成的數(shù)據(jù)庫操作,都不會立即提交到數(shù)據(jù)庫,需要調(diào)用Connection的commit方法才行。如果有語句執(zhí)行失敗,可以調(diào)用rollback來回滾。注意:如果Connection遇到未處理的SQLException異常時,系統(tǒng)將非正常退出,系統(tǒng)會自動回滾該事務(wù)。如果程序捕捉了該異常,則需要在異常處理中顯示回滾事務(wù)。 Connection提供了設(shè)置事務(wù)中間保存點的方法:setSavepoint,有2個方法可以設(shè)置中間點:Savepoint setSavepoint():在當(dāng)前事務(wù)中創(chuàng)建一個未命名的中間點,并返回該中間點的Savepoint對象。Savepoint setSavepoint(String name):當(dāng)前事務(wù)中創(chuàng)建一個具有指定名稱的中間點,并返回該中間點的Savepoint對象通常setSavepoint(String name)設(shè)置中間點的名稱,事務(wù)回滾并不是通過中間點的名稱進行回滾的,而是根據(jù)中間點對象進行回滾的。設(shè)置名稱只是更好的區(qū)分中間點對象,用Connection的rollback(Savepoint savepoint)方法即可完成回滾到指定中間點。
JDBC對事務(wù)的支持體現(xiàn)在三個方面:
1、自動提交模式(auto-commit mode)
Connection提供了一個auto-commit屬性來指定事務(wù)何時結(jié)束
2、當(dāng)auto-commit為true時,當(dāng)每個獨立SQL操作的執(zhí)行完畢,事務(wù)立即自動提交,也就是說每個SQL操作都是一個事務(wù)
一個獨立SQL操作什么時候算執(zhí)行完畢,JDBC規(guī)范是這樣定義的:
對數(shù)據(jù)操作語言(DML)和數(shù)據(jù)定義語言(DDL),語句一執(zhí)行完就視為執(zhí)行完畢
3、當(dāng)auto-commit為false時,每個事務(wù)都必須顯示調(diào)用commit方法進行提交,或者顯示調(diào)用rollback方法進行回滾。auto-commit默認為true
事務(wù)隔離級別(Transaction Isolation Levels)
JDBC定義了五種事務(wù)隔離級別:
- TRANSACTION_NONE JDBC驅(qū)動不支持事務(wù)
- TRANSACTION_READ_UNCOMMITTED 允許臟讀、不可重復(fù)讀和幻讀
- TRANSACTION_READ_COMMITTED 禁止臟讀,但允許不可重復(fù)讀和幻讀
- TRANSACTION_REPEATABLE_READ 禁止臟讀和不可重復(fù)讀,單運行幻讀
- TRANSACTION_SERIALIZABLE 禁止臟讀、不可重復(fù)讀和幻讀
保存點
JDBC定義了SavePoint接口,提供一個更細粒度的事務(wù)控制機制。當(dāng)設(shè)置了一個保存點后,可以rollback到該保存點處的狀態(tài),而不是rollback整個事務(wù)
首先,我們來看看現(xiàn)有的JDBC操作會給我們帶來什么重大問題,比如有一個業(yè)務(wù):當(dāng)我們修改一個信息后再去查詢這個信息,看似是一個簡單的業(yè)務(wù),實現(xiàn)起來也非常容易,但當(dāng)這個業(yè)務(wù)放在多線程高并發(fā)的平臺下,問題自然就出現(xiàn)了,比如當(dāng)我們執(zhí)行了一個修改后,在執(zhí)行查詢前有一個線程也執(zhí)行了修改語句,這時我們再執(zhí)行查詢,看到的信息就有可能與我們修改的不同。為了解決這一問題,我們必須引入JDBC事務(wù)機制,其實現(xiàn)代碼很簡單,給出示例代碼供大家參考:
- 詳解Java的MyBatis框架中的事務(wù)處理
- 詳解Java的JDBC API中事務(wù)的提交和回滾
- Java 事務(wù)詳解及簡單應(yīng)用實例
- Java Spring 事務(wù)回滾詳解
- 在Java的JDBC使用中設(shè)置事務(wù)回滾的保存點的方法
- Java事務(wù)的個人理解小結(jié)
- Java與Oracle實現(xiàn)事務(wù)(JDBC事務(wù))實例詳解
- java事務(wù)回滾失敗問題分析
- Java基于JDBC實現(xiàn)事務(wù),銀行轉(zhuǎn)賬及貨物進出庫功能示例
- Java使用jdbc連接MySQL數(shù)據(jù)庫實例分析
- Java實現(xiàn)的mysql事務(wù)處理操作示例
相關(guān)文章
SpringBoot使用Mybatis注解實現(xiàn)分頁動態(tài)sql開發(fā)教程
這篇文章主要為大家介紹了SpringBoot使用Mybatis注解實現(xiàn)分頁及動態(tài)sql開發(fā)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03Java Spring Boot實現(xiàn)簡易掃碼登錄詳解
這篇文章主要為大家詳細介紹了java Spring Boot實現(xiàn)app掃碼登錄功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-09-09Java中策略設(shè)計模式的實現(xiàn)及應(yīng)用場景
策略設(shè)計模式是Java中一種常用的設(shè)計模式,它通過定義一系列算法并將其封裝成獨立的策略類,從而使得算法可以在不影響客戶端的情況下隨時切換。策略設(shè)計模式主要應(yīng)用于系統(tǒng)中存在多種相似的算法、需要靈活調(diào)整算法邏輯或者需要擴展新的算法等場景2023-04-04詳解@ConfigurationProperties實現(xiàn)原理與實戰(zhàn)
這篇文章主要介紹了詳解@ConfigurationProperties實現(xiàn)原理與實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Java優(yōu)化for循環(huán)嵌套的高效率方法
這篇文章主要介紹了Java優(yōu)化for循環(huán)嵌套的高效率方法,幫助大家更好的提升java程序性能,感興趣的朋友可以了解下2020-09-09