事务
-
基本介绍
- 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 | ArithmeticException e) { 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()方法,不使用事务,可以发现结果如下:
发生异常后,1号的存款转出了 100元,2号没有收到100元,100元没了。
-
如果调用的是useTransaction()方法,使用事务(connection.setAutoCommit(false) 取消事务自动提交)结果如下:
没有变化,控制台打印了 “执行发生了异常,撤销执行的SQL”,出现了异常后try-catch并进行了事务的回滚
-