自己寫架構筆記(4)----JDBC如何利用事務去處理sql語句

1、JDBC中的事務

最簡單的事務的概念的總結

在一個方法中,同時存在多條更新類語句(insert delelte update),那麼這些語句需要以整體方式執行,要麼都成功,要麼都失敗,不可以拆分執行。
舉一個很簡單的例子,A和B兩個人,A從B中購買東西,A需要向B支付一定的費用,假如A、B各有9000元,A需要向B支付5000元,B需要收入5000元,這兩個操作就包含在一個事務之中,兩個操作需要以整體方式執行,不可以拆分,要麼都成功,要麼都失敗,絕不允許只有A支付了,B沒有收到的這樣的情況。

事務的四個特性

1、一致性:
事務在執行前後,數據的大小總和保持不變。
也就是在上面的例子中的A在支付前後,A和B的總金額都是18000,絕對不允許在這個事務執行之後,這個數據的總和發生改變。
2、原子性
構成事務的語句,以整體方式執行,要麼都成功,要麼都失敗。
3、持久性
事務做出的改變,一經確認,具有永久時效性,不可以再撤回。
4、隔離性
事務執行期間,涉及的數據暫時處於鎖定的狀態,其他事務不能處理.
事務的隔離性在數據庫底層是通過鎖機制完成的.
隔離性就好比java線程中的兩個線程不可以同時去修改一個數據,必須加上互斥鎖這樣的鎖,才能保證隔離性。

2、JDBC中採用事務的方式來執行sql語句

我們假定有兩個人,“武松”和“西門吹雪”兩個人做生意,後者需要向前者支付5000元,假定兩個人都有9000,我們在這裏偷偷的給武松的金錢的數據類型大小,設置成4位的,也就是不會超過9999,意思就是,就算收到了5000,也不會加進來稱爲自己的錢,那麼這個時候,我們再看西門吹雪是不是成功支付了,還是沒有成功呢?我們根據事務的原子性和一致性,也知道,是不會成功的,具體看一下代碼:
先看一下和數據庫有關的DBUtils類:

package com.neusoft.system.db;

import java.sql.*;
//資源文件解析器
import java.util.ResourceBundle;


public class DBUtils 
{
//1.定義驅動串---整個驅動jar包中,核心類的路徑
private static String driver=null;
//2.定義鏈接串---數據庫所在的位置及名稱
private static String url=null;
private static String userName=null;
private static String password=null;

/**
 * 靜態塊
 * 在類被第一次加載入內存時候,執行,以後不再執行
 */
static
{
    System.out.println("run static .......");
    try
    {
        //獲取資源文件解析器實例
        ResourceBundle bundle=ResourceBundle.getBundle("DBOPtions");
        //從資源文件獲取數據
        driver=bundle.getString("DRIVER");
        url=bundle.getString("URL");
        userName=bundle.getString("USERNAME");
        password=bundle.getString("PASSWORD");

        //3.加載驅動
        Class.forName(driver);
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
}   

/**
 * 當一個類中所有的成員(屬性和方法)都是static,那麼此時構造器應該私有
 */
private DBUtils() {}


public static Connection getConnection()throws Exception
{
    //4.創建鏈接
    Connection conn=DriverManager.getConnection(url, userName, password);
    return conn;
}






public static void close(PreparedStatement pstm)
{
    try
    {
        if(pstm!=null)
        {
            pstm.close();
        }
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
}

public static void close(Connection conn)
{
    try
    {
        if(conn!=null && !conn.isClosed())
        {
            conn.close();
        }
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
}

public static void main(String[] args) 
{
    try
    {
        System.out.println(DBUtils.getConnection());                    
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
}

}

事務的方式來執行更新操作:

package transaction;

import java.sql.*;
import com.neusoft.system.db.DBUtils;

public class Person 
{

public static void main(String[] args)
{
    try 
    {
        boolean tag=Person.tiger();
        System.out.println(tag);

    }
    catch (Exception e) 
    {
        e.printStackTrace();
    }
}

private static boolean tiger()throws Exception
{
    //1.定義JDBC接口
    Connection conn=null;
    PreparedStatement pstm1=null;   //扣減西門吹雪
    PreparedStatement pstm2=null;   //增加武松
    try
    {
        //2.創建連接
        conn=DBUtils.getConnection();

        //3.完成對西門吹雪賬戶的處理
        //3.1定義SQL語句
        String sql1="update person set umoney=umoney-? where uid=?";
        //3.2編譯SQL語句
        pstm1=conn.prepareStatement(sql1);
        pstm1.setObject(1, 5);
        pstm1.setObject(2, 2);

        //4.處理武松的賬戶
        //4.1定義SQL語句
        String sql2="update person set umoney=umoney+? where uid=?";
        //4.2編譯SQL及賦值
        pstm2=conn.prepareStatement(sql2);
        pstm2.setObject(1, 5);
        pstm2.setObject(2, 1);


        //5.以事務方式執行SQL
        //5.1定義事務返回值
        boolean tag=false;
        /**
         * 5.2開啓事務
         * conn內部存在一個叫autoCommit的屬性,該屬性默認值爲true,
         * 表示遇到更新類語句,立即修改數據庫
         * setAutoCommit(false);  遇到更新類語句,先不要修改數據庫,而是進行彩排(模擬執行),
         * 等待後繼指令,後繼指令如果是更新數據庫那麼再去更新,如果是撤銷,那麼取消更新操作
         */
        conn.setAutoCommit(false);
        try
        {
            //5.3在事務內部執行所有的更新語句
            pstm1.executeUpdate();
            pstm2.executeUpdate();

            //5.4.1:確認對數據的修改---提交事務
            conn.commit();
            //5.5修改事務返回值,表示執行成功
            tag=true;
        }
        catch(Exception ex)
        {
            //5.4.2:取消對數據的修改---事務回滾
            conn.rollback();
            ex.printStackTrace();
        }
        finally
        {
            //5.6結束事務
            conn.setAutoCommit(true);
        }
        return tag;

    }
    finally
    {
        DBUtils.close(pstm1);
        DBUtils.close(pstm2);
        DBUtils.close(conn);
    }
}



}

【注】
事務不提交,不會執行sql語句。
在捕捉到異常的時候,要進行事務的回滾,這樣纔不會出差錯。
JDBC結束之後,一定記得關閉連接資源,否則內存泄漏。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章