JavaWeb:JDBC之事务
系列閱讀
1. 事務
- 事務的四大特性:ACID
- mysql中操作事務
- jdbc中操作事務
1.1 事務概述
為了方便演示事務,我們需要創建一個account表:
CREATE TABLE account(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(30),balance NUMERIC(10.2) );INSERT INTO account(NAME,balance) VALUES('zs', 100000); INSERT INTO account(NAME,balance) VALUES('ls', 100000); INSERT INTO account(NAME,balance) VALUES('ww', 100000);SELECT * FROM account;1.2 什么是事務
銀行轉賬!張三轉10000塊到李四的賬戶,這其實需要兩條SQL語句:
- 給張三的賬戶減去10000元
- 給李四的賬戶加上10000元
如果在第一條SQL語句執行成功后,在執行第二條SQL語句之前,程序被中斷了(可能是拋出了某個異常,也可能是其他什么原因),那么李四的賬戶沒有加上10000元,而張三卻減去了10000元。這肯定是不行的!
你現在可能已經知道什么是事務了吧!事務中的多個操作,要么完全成功,要么完全失敗!不可能存在成功一半的情況!也就是說給張三的賬戶減去10000元如果成功了,那么給李四的賬戶加上10000元的操作也必須是成功的;否則給張三減去10000元,以及給李四加上10000元都是失敗的!
1.3 事務的四大特性(ACID)
事務的四大特性是:
原子性(Atomicity):事務中所有操作是不可再分割的原子單位。事務中所有操作要么全部執行成功,要么全部執行失敗
一致性(Consistency):事務執行后,數據庫狀態與其它業務規則保持一致。如轉賬業務,無論事務執行成功與否,參與轉賬的兩個賬號余額之和應該是不變的
隔離性(Isolation):隔離性是指在并發操作中,不同事務之間應該隔離開來,使每個并發中的事務不會相互干擾
持久性(Durability):一旦事務提交成功,事務中所有的數據操作都必須被持久化到數據庫中,即使提交事務后,數據庫馬上崩潰,在數據庫重啟時,也必須能保證通過某種機制恢復數據
1.4 MySQL中的事務
在默認情況下,MySQL每執行一條SQL語句,都是一個單獨的事務。如果需要在一個事務中包含多條SQL語句,那么需要開啟事務和結束事務。
- 開啟事務:start transaction
- 結束事務:commit或rollback
在執行SQL語句之前,先執行strat transaction,這就開啟了一個事務(事務的起點),然后可以去執行多條SQL語句,最后要結束事務,commit表示提交,即事務中的多條SQL語句所做出的影響會持久化到數據庫中。或者rollback,表示回滾,即回滾到事務的起點,之前做的所有操作都被撤消了!
下面演示zs給li轉賬10000元的示例:
START TRANSACTION; UPDATE account SET balance=balance-10000 WHERE id=1; UPDATE account SET balance=balance+10000 WHERE id=2; ROLLBACK;START TRANSACTION; UPDATE account SET balance=balance-10000 WHERE id=1; UPDATE account SET balance=balance+10000 WHERE id=2; COMMIT;START TRANSACTION; UPDATE account SET balance=balance-10000 WHERE id=1; UPDATE account SET balance=balance+10000 WHERE id=2; quit;2. JDBC事務
在jdbc中處理事務,都是通過Connection完成的!同一事務中所有的操作,都在使用同一個Connection對象!
2.1、JDBC中的事務
Connection的三個方法與事務相關:
- setAutoCommit(boolean):設置是否為自動提交事務,如果true(默認值就是true)表示自動提交,也就是每條執行的SQL語句都是一個單獨的事務,如果設置false,那么就相當于開啟了事務了
- commit():提交結束事務
- rollback():回滾結束事務
jdbc處理事務的代碼格式:
try {con.setAutoCommit(false);//開啟事務…….…con.commit();//try的最后提交事務 } catch() {con.rollback();//回滾事務 }public void transfer(boolean b) {Connection con = null;PreparedStatement pstmt = null;try {con = JdbcUtils.getConnection();//手動提交con.setAutoCommit(false);String sql = "update account set balance=balance+? where id=?";pstmt = con.prepareStatement(sql);//操作pstmt.setDouble(1, -10000);pstmt.setInt(2, 1);pstmt.executeUpdate();// 在兩個操作中拋出異常if(b) {throw new Exception();}pstmt.setDouble(1, 10000);pstmt.setInt(2, 2);pstmt.executeUpdate();//提交事務con.commit();} catch(Exception e) {//回滾事務if(con != null) {try {con.rollback();} catch(SQLException ex) {}}throw new RuntimeException(e);} finally {//關閉JdbcUtils.close(con, pstmt);}}3. 保存點
保存點是JDBC3.0的東西!當要求數據庫服務器支持保存點方式的回滾。
校驗數據庫服務器是否支持保存點!
保存點的作用是允許事務回滾到指定的保存點位置。在事務中設置好保存點,然后回滾時可以選擇回滾到指定的保存點,而不是回滾整個事務!注意,回滾到指定保存點并沒有結束事務!!!只有回滾了整個事務才算是結束事務了!
Connection類的設置保存點,以及回滾到指定保存點方法:
- 設置保存點:Savepoint setSavepoint()
- 回滾到指定保存點:void rollback(Savepoint)
4. 事務隔離級別
4.1 事務的并發讀問題
- 臟讀:讀取到另一個事務未提交數據
- 不可重復讀:兩次讀取不一致
- 幻讀(虛讀):讀到另一事務已提交數據
4.2 并發事務問題
因為并發事務導致的問題大致有5類,其中兩類是更新問題,三類是讀問題
- 臟讀(dirty read):讀到另一個事務的未提交更新數據,即讀取到了臟數據
- 不可重復讀(unrepeatable read):對同一記錄的兩次讀取不一致,因為另一事務對該記錄做了修改
- 幻讀(虛讀)(phantom read):對同一張表的兩次查詢不一致,因為另一事務插入了一條記錄
4.2.1 臟讀
事務1:張三給李四轉賬100元
事務2:李四查看自己的賬戶
- t1:事務1:開始事務
- t2:事務1:張三給李四轉賬100元
- t3:事務2:開始事務
- t4:事務2:李四查看自己的賬戶,看到賬戶多出100元(臟讀)
- t5:事務2:提交事務
- t6:事務1:回滾事務,回到轉賬之前的狀態
4.2.2不可重復讀
事務1:酒店查看兩次1048號房間狀態
事務2:預訂1048號房間
- t1:事務1:開始事務
- t2:事務1:查看1048號房間狀態為空閑
- t3:事務2:開始事務
- t4:事務2:預定1048號房間
- t5:事務2:提交事務
- t6:事務1:再次查看1048號房間狀態為使用
- t7:事務1:提交事務
對同一記錄的兩次查詢結果不一致!
4.2.3幻讀
事務1:對酒店房間預訂記錄兩次統計
事務2:添加一條預訂房間記錄
- t1:事務1:開始事務
- t2:事務1:統計預訂記錄100條
- t3:事務2:開始事務
- t4:事務2:添加一條預訂房間記錄
- t5:事務2:提交事務
- t6:事務1:再次統計預訂記錄為101記錄
- t7:事務1:提交
對同一表的兩次查詢不一致!
不可重復讀和幻讀的區別:
- 不可重復讀是讀取到了另一事務的更新;
- 幻讀是讀取到了另一事務的插入(MySQL中無法測試到幻讀);
4.3 四大隔離級別
4個等級的事務隔離級別,在相同數據環境下,使用相同的輸入,執行相同的工作,根據不同的隔離級別,可以導致不同的結果。不同事務隔離級別能夠解決的數據并發問題的能力是不同的
4.3.1 SERIALIZABLE(串行化)
- 不會出現任何并發問題,因為它是對同一數據的訪問是串行的,非并發訪問的
- 性能最差
4.3.2 REPEATABLE READ(可重復讀)(MySQL)
- 防止臟讀和不可重復讀,不能處理幻讀問題
- 性能比SERIALIZABLE好
4.3.3 READ COMMITTED(讀已提交數據)(Oracle)
- 防止臟讀,沒有處理不可重復讀,也沒有處理幻讀;
- 性能比REPEATABLE READ好
4.3.4 READ UNCOMMITTED(讀未提交數據)
- 可能出現任何事務并發問題
- 性能最好
MySQL的默認隔離級別為REPEATABLE READ,這是一個很不錯的選擇吧!
4.3.5 MySQL隔離級別
MySQL的默認隔離級別為Repeatable read,可以通過下面語句查看:
select @@tx_isolation也可以通過下面語句來設置當前連接的隔離級別:
set transaction isolationlevel [4先1]4.3.6 JDBC設置隔離級別
con. setTransactionIsolation(int level);參數可選值如下:
- Connection.TRANSACTION_READ_UNCOMMITTED
- Connection.TRANSACTION_READ_COMMITTED
- Connection.TRANSACTION_REPEATABLE_READ
- Connection.TRANSACTION_SERIALIZABLE
5. 事務總結
- 事務的特性:ACID
- 事務開始邊界與結束邊界:開始邊界(con.setAutoCommit(false)),結束邊界(con.commit()或con.rollback())
- 事務的隔離級別: READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。多個事務并發執行時才需要考慮并發事務
總結
以上是生活随笔為你收集整理的JavaWeb:JDBC之事务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaWeb:JDBC之数据库连接池
- 下一篇: JavaWeb监听器