JDBC如何處理事務和隔離級別

JDBC如何處理事務和隔離級別

事務和JDBC相關內容不再做介紹,可以去本人博客中看看:

這裏主要說一下在JDBC編程中如何處理事務?
和MySQL一樣,JDBC默認不開啓事務,每執行一個SQL便提交一次,在MySQL中我們需要set autocommit=0來開啓事務功能,然後用begin開始一個事務,用savepoint point1設置名爲point1的保存點,用rollback來回滾,用commit來提交。而在JDBC中,我們需要調用connection對象的一些方法:

  • connection.setAutoCommit(false);開啓事務功能
  • connection.commit();提交一個事務

我們先來看看上面兩個方法的使用:

import java.sql.*;

public class TranDemo {
    public static void select(Connection connection,String sql1) throws SQLException {
        PreparedStatement ps= null;
        try {
            ps = connection.prepareStatement(sql1);//預編譯sql1
	        ps.setString(1,"08");
            ResultSet resultSet = ps.executeQuery();
            while (resultSet.next()){
                System.out.println("SID="+resultSet.getString(1)+
                        " Sname="+resultSet.getString(2));
            }//我這裏爲了方便只打印SID和Sname
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是這個方法的局部變量,方法結束需要關閉ps
                ps=null;//防止內存泄露
            }
        }
    }
    
    public static void delete(Connection connection,String sql3){
        PreparedStatement ps= null;
        try {
            ps=connection.prepareStatement(sql3);//預編譯sql3
            ps.setString(1,"08");
            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是這個方法的局部變量,方法結束需要關閉ps
                ps=null;//防止內存泄露
            }
        }
    }
    public static void main(String[] args) {
        Connection connection=null;
        try {
            String sql1="select * from Student where SID=?";
            String sql3="delete from Student where SID=?";
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_sql", "root", "123456");
            //開啓事務功能
            connection.setAutoCommit(false);//false--不自動提交
            //此時事務功能就已經開啓
            //爲了看起來有條理,我把查詢、刪除SID='08'這條記錄的三個SQL語句的執行過程封裝起來
             select(connection,sql1);//先執行sql1,查詢SID='08',打印SID和Sname
            delete(connection,sql3);//再執行sql3,刪除SID='08'這條記錄
            select(connection,sql1);//查詢SID='08',看還能不能查到
             connection.commit();//對比下調用這個方法和不調用的區別
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                connection.close();
                connection=null;
            } 
        }
    }
}

當把 connection.commit();註釋起來時,執行結果如下:
在這裏插入圖片描述
可以看到兩次查詢同樣的數據只有一次的打印結果,證明刪除成功;
去MySQL中確認一下:
在這裏插入圖片描述
還查詢的出來,證明刪除失敗,Java代碼中執行的結果並沒有提交(commit)給MySQL。
來看看放開connection.commit();的註釋後的打印結果:
在這裏插入圖片描述
刪除成功,再看看數據庫中的數據:
在這裏插入圖片描述
查詢不到,證明刪除成功。
注意:事務中的緩存機制是將一個事務訪問的數據複製一份爲緩存(這裏說成副本/快照更合適)去操作,當調用commit時才把緩存的內容提交給數據庫。

  • connection.setSavepoint();設置一個保存點
  • connection.rollback()/connection.rollback(point1);回滾到初始狀態/point1狀態
    注意!!!正常寫程序時回滾語句要寫在拋SQLException異常的catch塊中,如果某個SQL語句執行失敗拋異常就可以回滾。

這裏爲了掩飾回滾效果就放在try塊中,方便演示:

import java.sql.*;

public class TranDemo {
    public static void select(Connection connection,String sql1) throws SQLException {
        PreparedStatement ps= null;
        try {
            ps = connection.prepareStatement(sql1);//預編譯sql1
            ps.setString(1,"02");
            ResultSet resultSet = ps.executeQuery();
            while (resultSet.next()){
                System.out.println("SID="+resultSet.getString(1)+
                        " Sname="+resultSet.getString(2));
            }//我這裏爲了方便只打印SID和Sname
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是這個方法的局部變量,方法結束需要關閉ps
                ps=null;//防止內存泄露
            }
        }
    }
  
    public static void delete(Connection connection,String sql3){
        PreparedStatement ps= null;
        try {
            ps=connection.prepareStatement(sql3);//預編譯sql3
            ps.setString(1,"02");
            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是這個方法的局部變量,方法結束需要關閉ps
                ps=null;//防止內存泄露
            }
        }
    }
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Savepoint point1=null;
        try {
            String sql1="select * from Student where SID=?";
            String sql3="delete from Student where SID=?";
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_sql", "root", "123456");
            //開啓事務功能
            connection.setAutoCommit(false);//false--不自動提交
            //此時事務功能就已經開啓
            //爲了看起來有條理,我把查詢、刪除SID='02'這條記錄的三個SQL語句的執行過程封裝起來
            select(connection,sql1);//1.先執行sql1,查詢SID='02',打印SID和Sname
             point1= connection.setSavepoint();//設置一個保存點point1
            delete(connection,sql3);//2.執行sql3,刪除SID='02'這條記錄
            select(connection,sql1);//查詢SID='02',不打印則刪除成功
            connection.rollback(point1);//回滾到point1
            select(connection,sql1);//打印出SID='02'的SID和Sname則回滾成功
            connection.commit();//對比下調用這個方法和不調用的區別,不能寫在rollback操作前
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(point1!=null){
                connection.releaseSavepoint(point1);
                point1=null;
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        }
    }
}

運行結果:
在這裏插入圖片描述
打印了兩次而不是三次,證明在事務的緩存(副本)中確實刪除了一次,最後又回滾到point1,刪除掉的數據又回來了。

  • connection.releaseSavepoint(point1);刪除point1保存點
  • connection.setTransactionIsolation(int level);設置事務的隔離級別,這個隔離級別只對當前連接有效,在MySQL中一個連接就是打開的一個窗口(終端);在JDBC中,一個連接就是一個connection。
    剖析源碼看一下隔離級別對應的int值:
    在這裏插入圖片描述
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章