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