【JDBC】笔记(4)--- JDBC 事务自动提交机制;账户转账演示事务代码(bug版+修正版)

楔子:

   JDBC 的事务默认是自动提交的:

   只要执行一条 DML语句,则自动提交一次。但是在实际的业务中,通常是多条 DML语句 联合完成的,那么就必须保证这些 DML语句 在同一个事务中同时成功或失败!!!

   否则这会是一个非常严重的bug!!!


/*
1、功能:实现转账功能(bug版)
2、需求:演示一下 JDBC事务 默认自动提交存在的隐患
3、t_act:(原表)
        +-------+---------+
        | actno | balance |
        +-------+---------+
        |  5566 | 1000.00 |
        |  1314 |    0.00 |
        +-------+---------+

*/

 

import java.sql.*;

/**
 *sql脚本:
 *  drop t_act if exists;
 *  create table t_act(
 *  actno int,
 *  balance double(7,2)
 *  );
 *  insert into t_act(actno,balance) values(5566,1000);
 *  insert into t_act(actno,balance) values(1314,0);
 */

public class JDBCTransactionTest01 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode"
                    , "root", "888");

            String sql = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql);
            ps.setDouble(1, 0);
            ps.setDouble(2, 5566);

            count = ps.executeUpdate();

            String s = null;
            s.toString();

            String sql0 = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql0);
            ps.setDouble(1, 1000);
            ps.setDouble(2, 1314);

            count += ps.executeUpdate();
            System.out.println("更新数据:" + count + "条");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(count == 2?"转账成功":"转账失败");
        }
    }
}

 

IDEA控制台输出结果:

java.lang.NullPointerException
	at com.bjpowernode.jdbc.JDBCTransactionTest01.main(JDBCTransactionTest01.java:48)
转账失败

Process finished with exit code 0

 

现在瞅一眼 t_act:

  +-------+---------+
  | actno | balance |
  +-------+---------+
  |  5566 |    0.00 |
  |  1314 |    0.00 |
  +-------+---------+

哎呀我去,这bug太严重了,钱都飞了!!


/*
1、功能:实现转账功能(修正版)                  

2、需求;使每次同一转账事务中,多条 DML语句 同时成功/同时失败

3、t_act:(原表)
        +-------+---------+
        | actno | balance |
        +-------+---------+
        |  5566 | 1000.00 |
        |  1314 |    0.00 |
        +-------+---------+

*/

 

import java.sql.*;

public class JDBCTransactionTest02 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement ps = null;
        int count = 0;

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode"
                    , "root", "888");

            //将自动提交机制修改为手动提交
            connection.setAutoCommit(false);

            String sql = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql);
            ps.setDouble(1, 0);
            ps.setDouble(2, 5566);

            count = ps.executeUpdate();

            String s = null;
            s.toString();

            String sql0 = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql0);
            ps.setDouble(1, 1000);
            ps.setDouble(2, 1314);

            count += ps.executeUpdate();
            System.out.println("更新数据:" + count + "条");

            //程序执行到这说明没有异常,事务结束,手动提交数据
            connection.commit();
        } catch (Exception e) {
            //如果出现异常,回滚事务
            if (connection != null) {
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(count == 2?"转账成功":"转账失败");
        }
    }
}

 

IDEA控制台输出结果:

java.lang.NullPointerException
	at com.bjpowernode.jdbc.JDBCTransactionTest02.main(JDBCTransactionTest02.java:31)
转账失败

Process finished with exit code 0

 

现在瞅一眼 t_act:

  +-------+---------+
  | actno | balance |
  +-------+---------+
  |  5566 | 1000.00 |
  |  1314 |    0.00 |
  +-------+---------+

虽然因为某些原因导致转账失败,但是数据库中储存的数据一切正常,而且控制台也给出了提示(转账失败),所以总结:此转账程序非常成功!


 

上一篇:状态模式(java)


下一篇:二叉树的创建和遍历