事务-模拟银行用户转账

SQL数据:

我这里准备了两个用户的数据,模拟一下在事务下的银行转账

DROP TABLE IF EXISTS `shiwu`;
CREATE TABLE `shiwu` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `money` double(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


INSERT INTO `shiwu` VALUES ('1', 'zhangsan', '1500.00');
INSERT INTO `shiwu` VALUES ('2', 'lisi', '2000.00');

+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 1500 |
| 2 | lisi | 2000 |
+----+----------+-------+

银行转账代码:

import java.sql.*;

public class Demo {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            ///2、获取连接(数据库对象)
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/donglijiedian", "root", "zhixi158");
            //3、关闭事务的自动提交,就是开启事务
            conn.setAutoCommit(false);

            //4、获取预编译的数据库操作对象(业务代码)
            String sql1 = "update shiwu set `money` = money+500 where `name` = 'zhangsan'";
            ps = conn.prepareStatement(sql1);
            //4.1、执行更新
            int count = ps.executeUpdate();

            /**
             * 如果让中间这个地方出现异常,那么余额就会是错误的了,第二条SQL语句并没有执行
             * 会出现:
             *  java.lang.NullPointerException(空指针异常)
             *  JDBC 中的事务是自动提交的:只要执行一条语句就提交一次
             * 解决办法:使用手动事务
             */
            //String s = null;
            //s.toString();

            String sql2 = "update shiwu set `money` = money-500 where `name` = 'lisi'";
            ps = conn.prepareStatement(sql2);
            count += ps.executeUpdate();

            System.out.println(count == 2 ? "转账成功" : "转账失败");
            //4.1.1、序能走到这里,说明上面没有出现异常,将事务进行手动提交
            conn.commit();
            //4.1.2、使用完毕后开启事务的自动提交
            conn.setAutoCommit(true);
        } catch (SQLException | ClassNotFoundException e) {
            //4.2、更新数据失败就回滚
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            //6、释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

测试:

原文地址:https://www.cnblogs.com/zhangzhixi/p/14110376.html