1. 程式人生 > >驗證mysql的自動提交事務和手動提交事務(java版)

驗證mysql的自動提交事務和手動提交事務(java版)

個人理解的一個事務:是一個Connection一系列的操作過程,如果是兩個Connection連線在操作,那就是兩個事務。

事務的前提:資料庫的儲存引擎是innodb。

事務的目的:保證資料的安全性。

事務安全
1.自動提交事務:每執行一條sql語句,就同步到資料庫中。
2.手動提交事務:執行一系列的sql語句後一起同步到資料庫中。

事務的四大特性
A(atomic):原子性,事務中的全部操作是一個整體,要麼全部成功,要麼全部失敗;
C(consistency):一致性:事務開啟後,資料表中的資料狀態沒有變化,因為還沒有提交;
I(Isolation):隔離型,多個事務操作是相互隔離,互不影響的;
D(Durability):永續性,事務一旦提交,資料表就發生永久改變.

自動提交事務和手動提交事務的區別:

自動提交事務:
在資料庫工具下的測試:

資料庫的資料:
資料庫的資料

自動提交事務執行select查詢的結果:
這裡寫圖片描述

用java程式碼測試自動提交事務時的測試結果:

    @Test
    //自動提交事務(隱形事務時)
    public void testNotAddAffair(){
        Connection con = JDBCTemple.getConnection();
        String sql = "select count(1) from sal_table";

        int count = 0
; try { //查詢操作 count = JDBCTemple.selectData(con,sql); System.out.println("(try中)插入前的count=" + count); //插入操作 String insert = "insert into sal_table(sname,sal) values(?,?)"; Object[] objs = {"王五", 2000}; JDBCTemple.updateDate(con,insert, objs); //再次查詢操作
count = JDBCTemple.selectData(con,sql); System.out.println("(try中)插入一條資料以後的count=" + count); //插入操作 //Object[] objs1 = {"王五他大哥", 2000}; JDBCTemple.updateDate(con,insert, null); count = JDBCTemple.selectData(con,sql); System.out.println("(try中)第二次插入後的count=" + count); } catch (Exception e1) { count = JDBCTemple.selectData(con,sql); System.out.println("(catch中)出現異常後count=" + count); e1.printStackTrace(); }finally{ System.out.println("(finally中)最終count=" + count); } }

執行結果如下:

這裡寫圖片描述

結果分析:
1.插入之前,第一次執行select查詢語句時,查詢到的結果是20,與工具中查的結果是一樣的。
2.插入後,第二次執行select查詢語句時,查詢到的結果為21,說明資料可能插入到資料庫中。
3.第二次插入時,因為引數是null,所以出現了空指標異常,沒有成功插入到資料庫中,sql執行出現異常,轉到catch{}程式碼塊中。
4.在catch{}程式碼塊中再次查詢,查詢到的結果為21,說明第一次資料已經插入到資料庫中。
5.在finally{}程式碼塊中再次查詢,查詢的資料還是21,說明最終第一次資料插入到資料庫,但是第二次沒有成功插入到資料庫中。

顯示提交事務
在資料庫工具下的測試:
手動提交事務執行select查詢的結果
這裡寫圖片描述

用java程式碼測試手動提交事務時的測試結果:

         @Test
        public void testAddAffair(){
            Connection con = JDBCTemple.getConnection();
            String sql = "select count(1) from sal_table";
            int count = 0;


            try {
                //事務的提交方式為手動提交
                con.setAutoCommit(false);

                //查詢操作
                count = JDBCTemple.selectData(con,sql);
                System.out.println("(try中)插入前的count=" + count);


                //插入操作
                System.out.println("開始第一次插入資料...");
                String insert = "insert into sal_table(sname,sal) values(?,?)";
                Object[] objs = {"王五", 2000};
                JDBCTemple.updateDate(con,insert, objs);
                System.out.println("第一次插入資料成功!");

                //再次查詢操作
                count = JDBCTemple.selectData(con,sql);
                System.out.println("(try中)插入一條資料以後的count=" + count);

                //插入操作
                System.out.println("開始第二次插入資料....");
                //Object[] objs1 = {"王五他大哥", 2000};
                JDBCTemple.updateDate(con,insert, null);
                System.out.println("第二次插入資料成功!");

                count = JDBCTemple.selectData(con,sql);
                System.out.println("(try中)插入兩條資料以後的count=" + count);

                //提交事務
                con.commit();
            } catch (Exception e1) {
                try {
                    con.rollback();
                    count = JDBCTemple.selectData(con,sql);
                    System.out.println("(catch(try)中)回滾後的count=" + count);
                } catch (SQLException e) {
                    System.out.println("回滾失敗!");
                    e.printStackTrace();
                }

                count = JDBCTemple.selectData(con,sql);
                System.out.println("(catch中)的count=" + count);
                e1.printStackTrace();
            }finally{
                count = JDBCTemple.selectData(con,sql);
                System.out.println("(finally中)最終count=" + count);
            }
        }

執行結果如下:
這裡寫圖片描述

結果分析:
很明顯的一點是:顯示提交事務時,如果出現異常,那麼執行結果和未執行sql語句之前的結果是一樣的。
1.插入之前,第一次執行select查詢語句時,查詢到的結果是21,與工具中查的結果是一樣的。
2.插入後,第二次執行select查詢語句時,查詢到的結果為22,說明這條資料可能插入到資料庫中。
3.第二次插入時,因為引數是null,所以出現了空指標異常,沒有成功插入到資料庫中,sql執行出現異常,轉到catch{}程式碼塊中。
4.在catch{}程式碼塊中再次查詢,查詢到的結果為21,又回到了第一條資料沒有插入之前的結果。
5.在finally{}程式碼塊中再次查詢,查詢的資料還是21,說明第一次的插入最終沒有同步到資料庫中

那麼問題出現了,第一次插入的資料最終沒有同步到資料庫中,那麼第一次插入後查詢到的資料條數是22,這是為什麼?屬於幻讀嗎?
對於以上結果做以下分析:
1.原子性:以上所有的操作共用一個客戶端的Connection物件,因為顯示提交事務,所以為了保證資料的原子性,try{}程式碼塊中的所有更新 操作屬於不可分割的一部分,要麼全部成功,要麼全部失敗。
2.是否屬於幻讀的問題:如果單單理解幻讀史兩次讀取資料的行數結果不一樣,那麼這確實是幻讀。但是真正幻讀的概念是兩次讀取資料中間的時間間隔內,有其他的事務(其他的Connection連線)對錶中資料進行了更新的操作,導致兩次資料不一致的問題。在這個小demo中,始終用的是同一個Connection連結,屬於同一個事務,所以不屬於幻讀。
3.理解第一次插入後查詢到的資料條數是22,就要理解事務操作時資料庫執行過程,請看下圖:
這裡寫圖片描述
從上圖我們知道這個22的出現是因為:第一次插入的資料寫入到了日誌檔案中,當我們在第一次插入後查詢資料時,先從資料庫表格中查到資料21,再經過日誌檔案處理,變成22,此時資料庫表格中並沒有更新。當第二次插入資料失敗時,回滾資料,將日誌中的記錄刪除,最終沒有將第一次的資料同步到資料庫中,所以最終資料庫中的記錄數還是21.