Java學習日誌(三十五): 事務,三層思想實現轉賬案例

JavaEE學習日誌持續更新----> 必看!JavaEE學習路線(文章總彙)

事務

事務概述

事務指的是邏輯上的一組操作,組成這組操作的各個單元要麼全都成功,要麼全都失敗。
事務作用:保證在一個事務(一個connection)中多次SQL操作要麼全都成功,要麼全都失敗。 防止出現轉賬吞錢的現象。

數據庫有事務概念,執行sql語句,就會開啓事務,執行成功會提交事務,執行失敗會回滾事務:

  • mysql數據庫事務默認都是自動的,自動開啓事務,自動提交事務,自動回滾事務
  • oracle數據庫事務默認都是手動的,手動開啓事務,手動提交事務,手動回滾事務

注意:事務一旦結束(提交,回滾),數據就永久保存在數據庫

在Connection接口中,有操作事務的方法

  • void setAutoCommit​(boolean autoCommit) 將此連接的自動提交模式設置爲給定狀態。

     參數:
       autoCommit:true啓用自動提交模式(默認);
                   false禁用自動提交模式,(執行sql語句之前)手動開啓事務。
    
  • void commit() 一組sql一句都執行成功,提交事務

  • void rollback() 一組sql中有一條執行失敗,回滾事務;把數據回滾到數據開啓之前

使用原生JDBC完成轉賬案例

首先,創建一張賬戶表

# 創建一個表:賬戶表.
CREATE DATABASE day05;
# 使用數據庫
USE day05;
# 創建賬號表
CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	money DOUBLE
);
# 初始化數據
INSERT INTO account VALUES (NULL,'jack',10000);
INSERT INTO account VALUES (NULL,'rose',10000);
INSERT INTO account VALUES (NULL,'tom',10000);

在這裏插入圖片描述
代碼示例:使用原生JDBC完成轉賬案例

public class Demo01JDBC {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stat = null;
        try {
            //註冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            //獲取數據庫連接對象Connection
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day05", "root", "root");

            //開啓事務
            conn.setAutoCommit(false);

            //獲取執行者對象Statement
            stat = conn.createStatement();
            //執行sql語句獲取結果
            int row1 = stat.executeUpdate("UPDATE account SET money=money-1000 where NAME='jack';");
            System.out.println(0/0);
            int row2 = stat.executeUpdate("UPDATE account SET money=money+1000 where NAME='rose';");
            //處理結果
            if (row1 > 0 && row2 > 0) {
                System.out.println("轉賬成功");
                //提交事務
                conn.commit();
            }
        } catch (Exception e) {
            System.out.println("轉賬失敗");
            e.printStackTrace();
            /*
                回滾事務
             */
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            //釋放資源
            if(stat!=null){
                try {
                    stat.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

使用DbUtils和C3P0完成轉賬案例

QueryRunner的構造方法:

  • QueryRunner():空參構造,調用update/query方法執行sql語句時,必須傳遞Connection對象。
  • QueryRunner(DataSource ds):帶連接池的構造方法,看不到Connection,也就不能操作事務。

QueryRunner的成員方法:用於執行增刪改的update方法。
int update(Connection conn,String sql,Object... params) 空參構造使用。

代碼示例:使用DBUtils+C3P0連接池完成轉賬案例

public class Demo02DBUtils {
    public static void main(String[] args) {
        //1.創建QueryRunner對象
        QueryRunner qr = new QueryRunner();
        //2.使用C3P0連接池獲取Connection
        Connection conn = C3P0UtilsXML.getConnection();

        //3.使用QueryRunner對象中的方法update
        String sql1 = "UPDATE account SET money=money-1000 where NAME='jack';";
        String sql2 = "UPDATE account SET money=money+1000 where NAME='rose';";
        try {
            //開啓事務
            conn.setAutoCommit(false);

            int row1 = qr.update(conn, sql1);
            int row2 = qr.update(conn, sql2);
            //4.處理結果
            if (row1 > 0 && row2 > 0) {
                System.out.println("轉賬成功");
                //提交事務
                conn.commit();
            }
        } catch (Exception e) {
            System.out.println("轉賬失敗");
            e.printStackTrace();
            //回滾事務
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            //釋放資源
            DbUtils.closeQuietly(conn);
        }
    }
}

三層思想

三層思想概述

在這裏插入圖片描述

三層思想轉賬案例_dao層

創建轉賬案例的Dao層:用於對account表進行增刪改查
注意:
一張表–>一個dao
定義兩個方法:
一個減錢,一個加錢

代碼示例:dao層

public class AccountDao {
    /*
        定義減錢方法
        參數:
            Connection conn:兩個方法使用同一個Connection,從而保證使用同一個事務
            String fromName:付款人姓名
            double money:轉賬金額
        返回值:
            int:影響數據庫的有效行數
        String sql1 = "UPDATE account SET money=money-1000 where NAME='jack';";
        String sql2 = "UPDATE account SET money=money+1000 where NAME='rose';";
     */
    public int fromAccount(Connection conn, String fromName, double money) throws SQLException {
        //創建QueryRunner對象
        QueryRunner qr = new QueryRunner();
        //調用update方法執行sql語句,接收結果
        int row = qr.update(conn,"UPDATE account SET money=money-? where NAME=?;",money,fromName);
        //返回方法
        return row;

    }
    /*
        定義加錢方法
        參數:
            Connection conn:兩個方法使用同一個Connection,從而保證使用同一個事務
            String toName:收款人姓名
            double money:轉賬金額
        返回值:
            int:影響數據庫的有效行數
        String sql1 = "UPDATE account SET money=money-1000 where NAME='jack';";
        String sql2 = "UPDATE account SET money=money+1000 where NAME='rose';";
     */
    public int toAccount(Connection conn, String toName, double money) throws SQLException {
        //創建QueryRunner對象
        QueryRunner qr = new QueryRunner();
        //調用update方法執行sql語句,接收結果
        int row = qr.update(conn,"UPDATE account SET money=money+? where NAME=?;",money,toName);
        //返回方法
        return row;

    }
}

三層思想轉賬案例_service層

轉賬案例的Service層:接收web層傳遞的數據,調用dao層的方法,接收結果;把結果返回給web層
定義一個轉賬方法

  1. 參數接收web傳遞的數據(付款人姓名,收款人姓名,轉賬金額)
  2. 使用C3P0連接池,獲取Connection
  3. 開啓事務
  4. 創建AccountDao對象,調用減錢價錢方法,接收結果
  5. 對結果進行判斷
  6. 執行成功,提交事務;有異常回滾事務
  7. 把結果返回給web層
  8. 釋放資源

代碼示例:service層

public class AccountService {
    //定義一個轉賬方法
    public boolean transferAccount(String fromName, String toName, double money) {
        //使用C3P0連接池,獲取Connection
        Connection conn = C3P0UtilsXML.getConnection();
        //定義返回的結果
        boolean flag = false;
        try {
            //開啓事務
            conn.setAutoCommit(false);
            //創建AccountDao對象
            AccountDao dao = new AccountDao();
            //調用減錢價錢方法,接收結果
            int row1 = dao.fromAccount(conn, fromName, money);
            int row2 = dao.toAccount(conn, toName, money);
            //對結果進行判斷
            if (row1>0&&row2>0){
                flag = true;
                //執行成功,提交事務
                conn.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
            //有異常回滾事務
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            //資源釋放
            DbUtils.closeQuietly(conn);
        }
        //把結果返回給web層
        return flag;
    }
}

三層思想轉賬案例_web層

創建轉賬案例的web層

  1. 使用Scanner獲取用戶輸入的數據(付款人姓名,收款人姓名,轉賬金額)
  2. 創建AccountService對象
  3. 調用轉賬方法,接收轉賬結果
  4. 對結果進行判斷,給用戶展示結果

代碼示例:web層

public class AccountWeb {
    public static void main(String[] args) {
        //使用Scanner獲取用戶輸入的數據(付款人姓名,收款人姓名,轉賬金額)
        Scanner sc = new Scanner(System.in);
        System.out.print("請輸入付款人姓名:");
        String fromName = sc.next();
        System.out.print("請輸入收款人姓名:");
        String toName = sc.next();
        System.out.print("請輸入轉賬金額:");
        double money = sc.nextDouble();
        //創建AccountService對象
        AccountService service = new AccountService();
        //調用轉賬方法,接收轉賬結果
        boolean b = service.transferAccount(fromName, toName, money);
        //對結果進行判斷,給用戶展示結果
        if (b) {
            System.out.println("轉賬成功");
        } else {
            System.out.println("轉賬失敗");
        }
    }
}

轉賬結果:
在這裏插入圖片描述

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