天天看點

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

事務。MySQL事務是對于更新(插入,修改,删除)來說的,查詢好像沒有事務不事務一說。

目錄

一:JDBC事務介紹 

1.事務及事務區:

(1)【commit送出】

(2)【rollback復原】

2.JDBC兩種事務模式:​

(1)自動送出事務模式:

(2)手動送出事務模式:

二:事務案例

1.沒有使用【手動送出事務】模式時

(1)TransactionSample類編寫

(2)運作結果 

(3)原因分析

2.使用【手動送出事務】模式時

(1)TransactionSample類編寫(出錯的時候)

(2)運作結果:(出錯的時候)

(3)程式沒有出錯,正常執行

一:JDBC事務介紹 

MySQL之是以能在實際中使用,就是因為其有事務機制。MySQL,Oracle這樣的關系型資料庫都是支援事務的;也有很多小衆的資料庫是不支援事務的。

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

1.事務及事務區:

(1)【commit送出】

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

● 應用程式在寫入資料時,并不是直接把資料放入到表中,而是先把資料放在事務區中;

● 事務區是MySQL自帶的;如果資料很小的時候,事務區中的資料放在記憶體中,以加快處理速度;如果資料比較大的時候,其會用一塊硬碟空間作為事務緩沖;

以A借給B100元為例:

       首先,程式對A的餘額作了減法操作,這是一個寫操作,但是其不會直接反映到資料表中,而是先把這個操作的中間結果放在事務區中;

       然後,程式對B的餘額作了加法的操作,同樣會把處理的中間結果放在事務區中

       最後,當程式對這兩個更新操作全部執行完以後,會主動的向MySQL發起一個commit送出的指令,這個commit送出指令會直接作用到MySQL事務區上;當MySQL看到程式進行commit事務送出後,于是MySQL的事務區會将剛才的加和減兩個操作一次性的寫入到資料表中;

        即,進行程式的寫操作的時候,兩次的記錄更新都是面向事務區的;隻有當進行commit送出的時候,才由事務區真正的反映到資料表中(啰嗦一下:對于真正寫入到資料表中的操作叫做“commit送出”);

        當送出成功後,事務區中的資料的資料就沒有意義了,由MySQL自動的把這個事務區清空,等待下一次應用程式再向事務區中進行新資料的寫入。

……………………………………………………

(2)【rollback復原】

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

以A借給B100元為例:

        程式【對A的餘額作了減法操作】操作正常;但是,由于某種原因程式【對B的餘額作了加法的操作】的時候,程式報錯了;那麼JDBC的應用程式會向事務區發起一個【rollback復原指令】;MySQL收到了這個復原指令以後,其會直接将在事務區中原本已經處理好的【對A的餘額作了減法操作】給清空;

        即程式一旦向MySQL送出了【rollback復原指令】以後,無論之前做了多少資料的前置處理,MySQL都會直接将事務區清空,最終的資料表中不會産生任何實質的寫入操作;

事務總結一句話:作為事務來說,要麼一次性全部完成;要麼将之前所有已經做的事情通過復原全部撤銷。

實際的Java代碼,主要是通過控制【commit送出】和【rollback復原】指令的時機,隻有應用程式發起了這樣的指令,MySQL才可以執行對應的操作。

……………………………………………………

2.JDBC兩種事務模式:
JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

(1)自動送出事務模式:

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

自動送出事務模式是JDBC的預設模式。在每一次執行寫操作(新增、修改、删除)的時候,每完成一次SQL語句都會自動的送出事務;

如果在程式中沒有顯式的寫【conn.setAutoCommit(true)】,其預設就是自動送出事務模式;

因為每一次執行寫操作(新增、修改、删除)的以後,其都會立即送出;;是以,複雜的業務(需要多條寫操作一起)的情況下,無法保證多資料的一緻性;

……………………………………………………

(2)手動送出事務模式:

commit()方法和rollback()方法都是Connection接口中定義的;

話句話說,事務設定為手動送出,事務的的送出和事務復原,都是需要通過Connection連接配接來調用方法實作的。很顯然,因為事務本來就是對于一次資料庫連接配接來說的嘛!!!!!
JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

二:事務案例

比如,一個公司入職1000個員工,這1000個人要麼一次性全部入職,要麼一個都不入職。像這種要麼全做,要麼什麼都不做的事情,基于資料庫的事務進行處理,是非常合适的。

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

1.沒有使用【手動送出事務】模式時

(1)TransactionSample類編寫

TransactionSample類:

(1)沒有使用事務;(2)預期要求是,1000個人要麼全部入職,要麼一個也不入職;(3)為了模拟過程中出現的程式報錯終端,使用了一個抛出異常(沒有對這個抛出的異常捕獲啦,目的就是使程式中斷執行);

package com.imooc.jdbc.sample;

import com.imooc.jdbc.common.DbUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TransactionSample {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = DbUtils.getConnection();
            String sql = "insert into employee(eno,ename,salary,dname) values(?,?,?,?)";
            for (int i = 4000; i < 5000; i++) {
                if (i == 4005) {
                    throw new RuntimeException("插入失敗");
                }
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, i);
                pstmt.setString(2, "員工" + i);
                pstmt.setFloat(3, 4000);
                pstmt.setString(4, "市場部");
                pstmt.executeUpdate();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            DbUtils.closeConnection(null,pstmt,conn);
        }

        System.out.println("你好啊。");
    }
}
           

(2)運作結果 

運作結果:運作結果不符合預期(1000個人要麼全部入職,要麼一個都不要入職);

額外說明一點:因為上面程式中是抛出的【RuntimeException】,而在catch塊中沒有對【RuntimeException】的捕獲,是以異常發生的時候,程式會中斷,是以最後的【System.out.println("你好啊。");】沒有執行。
JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例
JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

(3)原因分析

失敗原因分析:

        ● 預設情況下,JDBC會使用自動送出的模式;

        ● 自動送出:在前面執行的過程中,每執行一次update,即每執行一次【pstmt.executeUpdate();】,就立馬對資料進行送出。是以,上面會出現【程式中斷,但資料表中卻出現了5條資料】的情況。

為了解決這個問題,需要在得到資料庫連接配接對象之後,對其進行設定,以采用【手動送出事務】模式;

2.使用【手動送出事務】模式時

(1)TransactionSample類編寫(出錯的時候)

事務的設定,都是針對Connection對象來的!!!

package com.imooc.jdbc.sample;

import com.imooc.jdbc.common.DbUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TransactionSample {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = DbUtils.getConnection();
            conn.setAutoCommit(false);  // 關閉自動送出;
            String sql = "insert into employee(eno,ename,salary,dname) values(?,?,?,?)";
            for (int i = 4000; i < 5000; i++) {
                if (i == 4005) {
                    throw new RuntimeException("插入失敗");
                }
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, i);
                pstmt.setString(2, "員工" + i);
                pstmt.setFloat(3, 4000);
                pstmt.setString(4, "市場部");
                pstmt.executeUpdate();
            }
            conn.commit();//送出資料
        }catch (Exception e) { //一旦上面在執行的過程中,抛出裡異常;在catch塊中,必須要對其進行捕捉;
            e.printStackTrace();
            try {
                if (conn != null && conn.isClosed() == false) {
                    conn.rollback();  //資料復原
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            DbUtils.closeConnection(null, pstmt, conn);
        }

        System.out.println("你好啊。");
    }
}
           

(1)當【conn.setAutoCommit(false); 】關閉自動送出後,每一次執行【pstmt.executeUpdate();】的時候,所産生的中間資料會被放入到事務區中;

(2)在程式報錯,捕捉異常,然後進行復原的時候,catch塊隻保留了最大的【catch (Exception e)】;;;;;然後把復原的操作放在了catch塊中,這或許也是為什麼隻留最大的Exception的原因吧,。

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

(3)異常被捕獲後,程式不會中中斷,會繼續執行;

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

(2)運作結果:(出錯的時候)

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例
JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

(3)程式沒有出錯,正常執行

當程式正常執行的時候:

把這個異常抛出給注釋掉,這個過程會正常執行;

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例

運作效果:

JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例
JDBC入門九:JDBC實作事務(十分重要!!!)一:JDBC事務介紹 二:事務案例
在實際開發中,大多數的應用都是需要手動事務控制的。尤其是在金融項目中,資料強一緻性的業務,必須要基于資料庫的事務,而且要手動控制事務。

自我感覺,在實際中,某個業務所需的全部SQL操作,需要寫在一個資料庫連接配接(Connection對象)中,技術上是可以操作的,隻是見得情況不多,沒有感性的認識。