笑看天下无敌手 发表于 2023-7-27 20:32:53

JDBC p3 事务

事务


[*]基本介绍

[*]JDBC 程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
[*]JDBC程序中为了多个SQL语句作为一个整体执行,需要使用事务。
[*]调用 Connection 的 setAutoCommit(false) 可以取消自动提交事务(相当与开启了事务)。
[*]在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务。
[*]在其中某个操作失败或出现异常时,调用 rollback(); 方法回滚事务。

[*]案例:模拟经典的转账的业务
MySQL代码:
CREATE TABLE account(
        id INT PRIMARY KEY AUTO_INCREMENT,
        name VARCHAR(32) NOT NULL DEFAULT '',
        balance DOUBLE NOT NULL DEFAULT 0
) CHARACTER SET utf8;

INSERT INTO account VALUES(NULL, '马云', 3000);
INSERT INTO account VALUES(NULL, '马化腾', 10000);

SELECT * FROM account;Java代码:
package com.hspedu.jdbc.transaction_;

import com.hspedu.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;

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

/**
* Description: 演示在jdbc 中如何使用事务
*/
public class Transaction_ {

    //没有使用事务,模拟银行转账出现异常
    @Test
    public void noTransaction(){
      //1. 得到连接
      Connection connection = null; //默认情况下,connection 默认自动提交, 执行一句sql语句,就会提交事务

      //2. SQL语句
      String sql = "update account set balance = balance - 100 where id = ?";
      String sql2 = "update account set balance = balance + 100 where id = ?";

      PreparedStatement preparedStatement = null;

      //3. 创建PreparedStatement 对象
      try {

            connection = JDBCUtils.getConnection();

            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);
            preparedStatement.executeUpdate();

             int i = 1 / 0; //抛出异常接下来的语句就不会执行
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.setInt(1, 2);

            preparedStatement.executeUpdate();
      } catch (SQLException e) {
            e.printStackTrace();
      }finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
      }
    }


    //使用事务
    @Test
    public void UseTransaction() {
      //1. 得到连接
      Connection connection = null; //默认情况下,connection 默认自动提交, 执行一句sql语句,就会提交事务

      //2. SQL语句
      String sql = "update account set balance = balance - 100 where id = ?";
      String sql2 = "update account set balance = balance + 100 where id = ?";

      PreparedStatement preparedStatement = null;

      //3. 创建PreparedStatement 对象
      try {

            connection = JDBCUtils.getConnection();
            connection.setAutoCommit(false);//相当与开启了事务

            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);
            preparedStatement.executeUpdate();

            int i = 1 / 0; //抛出异常接下来的语句就不会执行
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.setInt(1, 2);
            preparedStatement.executeUpdate();

            //这里提交事务
            connection.commit();
      } catch (SQLException| ArithmeticExceptione) {
            System.out.println("执行发生了异常,撤销执行的SQL");
            e.printStackTrace();
            //可以在这里进行回顾,即撤销执行的sql语句
            try {
                connection.rollback();//默认回滚到事务开始的时候,可以填入回滚点savePoint
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
      } finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
      }
    }
}
[*]模拟1号向2号转账100元转账异常,调用noTransaction()方法,不使用事务,可以发现结果如下:
https://img2023.cnblogs.com/blog/3008601/202307/3008601-20230727203721624-1253988694.png
发生异常后,1号的存款转出了 100元,2号没有收到100元,100元没了。
[*]如果调用的是useTransaction()方法,使用事务(connection.setAutoCommit(false) 取消事务自动提交)结果如下:
https://img2023.cnblogs.com/blog/3008601/202307/3008601-20230727203736229-434220920.png
没有变化,控制台打印了 “执行发生了异常,撤销执行的SQL”,出现了异常后try-catch并进行了事务的回滚


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: JDBC p3 事务