Java程序设计——事务管理(JDBC编程)

目录

一、事务

二、保存点

三、批量更新


一、事务

事务是由一步或几步数据库操作序列组成的逻辑执行单元,这些序列要么都执行,要么都不执行

事务的四个特性:

  • 原子性:事务是最小执行单位,具有不可再分的特性,事务中的操作要么都执行,要么都不执行
  • 一致性:事务执行前和执行后,数据库都处于一致性状态
  • 隔离性:各事务的执行互不干扰,任意一个事物的内部操作对其它事务都是隔离的
  • 持久性:事务一旦提交,对数据库所做的任何操作都永久地记录到存储器中

事务处理过程的三个概念:

  • 事务提交:指成功执行事务,事务提交又分两种方式:显式提交(commit)和自动提交(正常执行完毕)
  • 事务中止:指未能成功完成事务,从而执行中断
  • 事务回滚:指对事务中止所造成的的变更需要进行撤销处理,数据库返回事务执行前的状态,事务回滚又分两种方式:显式方式(rollback)和自动回滚(系统错误或强行退出)

事务操作的具体步骤:

  1. 开启事务
  2. 执行任意条DML语句
  3. 执行成功,则提交事务
  4. 执行失败,则回滚事务

注意:

Connection接口在默认情况下会自动提交,即事务是关闭的,即一条SQL语句执行成功后,系统会立即调用commit()方法提交到数据库,而无法对其进行rollback回滚操作

通过调用Connection对象的setAutoCommit(boolean bool)方法可以开启或者关闭自动提交模式

代码:

//    开启事务(关闭自动提交)
con.setAutoCommit(false);

//    提交事务
con.commit();

//    回滚事务
con.rollback();

实例演示:


import java.sql.*;

public class EventManagementDemo {

    //    JDBC控制事务
    //    事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

    private static String driver = "com.mysql.cj.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
    private static String user = "root";
    private static String password = "root";

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        int count = 0;
        try {
            connection = DriverManager.getConnection(url,user,password); // 获取数据库连接对象
            String sql = "UPDATE tb_student SET studentName=? WHERE studentNo=?";
            pstmt = connection.prepareStatement(sql);
            pstmt.setString(1, "张三");
            pstmt.setInt(2,2013110101);

            // ------开启事务-------         // 同时成功/同时失败
            connection.setAutoCommit(false);// 在执行sql语句之前开启事务

            count = pstmt.executeUpdate();
            System.out.println("更新" + count + "条记录");
            String sql_select = "SELECT * FROM tb_student";
            pstmt = connection.prepareStatement(sql_select);
            rs = pstmt.executeQuery();
            while(rs.next()){
                int no = rs.getInt(1);
                String name = rs.getString(2);
                System.out.println(no+"\t"+name);
            }

            int exception = 5/0;          // 手动制造异常
            /*
                通过实验可以得知:
                       在程序出错的情况下:
                           如果不开启事务管理,程序在执行到错误到错误代码片段时,
                           执行sqi语句的对象依然可以对数据库的数据进行修改,

                           反之,如果开启事务管理,
                           执行到错误代码片段时,执行sql语句的对象无法对数据库里面的数据进行操作
             */

            //  ------提交事务-------
            connection.commit();           // 当所有sql语句都执行完提交事务

        } catch (SQLException e) {

            //   ------回滚事务-------
            try {
                connection.rollback();     // 在catch中回滚事务
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }
        finally {
            if (rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (pstmt != null){
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        }

    }

}

根据结果集返回的数据可知,JDBC似乎成功修改了数据库中数据表的信息,但由于开启了事务管理,所以出现事务中断时,JDBC对数据库的修改并未起作用,而是恢复到了执行前的状态

执行SQL语句后的数据表:


二、保存点

JDBC通过保存点,可以更好地控制事物回滚

原数据表:

import java.sql.*;

public class SavePointDemo {

//    JDBC还支持保存点操作,通过保存点,可以更好的控制事务回滚
//    保存点是事务中的逻辑回滚点
//    设置保存点时,只要在保存点之后发生错误,就可以使用该rollback()方法撤消在保存点之前所做的事件。

    private static String driver = "com.mysql.cj.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
    private static String user = "root";
    private static String password = "root";

    public static void main(String[] args) {
        Connection connection = null;
        Savepoint savepoint = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            Class.forName(driver);
            connection = DriverManager.getConnection(url,user,password); // 获取数据库连接对象
            //  -------开启事务-------
            connection.setAutoCommit(false);
            String sql1 = "INSERT INTO tb_student VALUES(2014310103,'张三','男','2022-7-5','北京','汉',null)";
            pstmt = connection.prepareStatement(sql1);
            pstmt.executeUpdate();

            //  设置保存点
            savepoint = connection.setSavepoint();
            String sql2 = "INSERT INTO tb_student VALUES(2014310104,'李四','女','2022-7-6','上海','满',null )";
            pstmt = connection.prepareStatement(sql2);
            pstmt.executeUpdate();

            //  回滚保存点
            connection.rollback(savepoint);

            //  ------提交事务-------
            connection.commit();           // 当所有sql语句都执行完提交事务

            //  -----恢复原有事务提交状态------
            connection.setAutoCommit(true);

        } catch (SQLException | ClassNotFoundException e) {
            //   ------回滚事务-------
            if(connection != null){
                try {
                    connection.rollback();     // 在catch中回滚事务
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            }
        }
        finally {
            if (rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (pstmt != null){
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        }

    }

}

上述代码首先声明了一个Savepoint对象,然后在执行第一条数据插入操作后调用setSavepoint()方法设置保存点,执行完第二条插入操作后,事物回滚到保存点

进行插入操作后的数据表显示,在保存点之前执行的插入操作成功,而保存点之后执行操作失效


三、批量更新

批量更新:即多条SQL语句将作为一批操作被同时收集,并同时提交

批量更新需得到底层数据库的支持,通过调用DatabaseMetaData接口的supports()方法来查看底层数据库是否支持批量更新

批量更新的步骤:

  1. 创建一个Statement对象
  2. 调用Statement对象的addBatch()方法收集多条SQL语句
  3. 调用Statement对象的execteBatch()或executeLargeBatch()方法同时执行所有的SQL语句

 

原数据表:

import java.sql.*;

public class DatabaseMetaDataDemo{

//    JDBC提供了批量更新功能,多条SQL语句将被作为一批操作被同时收集、提交
//    通过调用DatabaseMetaData的supports()来查看底层数据库是否支持批量更新

    private static String driver = "com.mysql.cj.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
    private static String user = "root";
    private static String password = "root";

    public static void main(String[] args) {
        Connection connection = null;
        Statement stmt = null;
        ResultSet rs = null;
        int count = 0;
        try {
            connection = DriverManager.getConnection(url, user, password); // 获取数据库连接对象

            // 1.创建一个statement对象
            stmt = connection.createStatement();

            // 2.使用statement对象的addBatch方法收集多条sql语句
            String sql1 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='狗蛋'";
            String sql2 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='王一敏'";
            String sql3 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='江山'";
            String sql4 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='李明'";
            stmt.addBatch(sql1);
            stmt.addBatch(sql2);
            stmt.addBatch(sql3);
            stmt.addBatch(sql4);

            // 3.调用statement对象的excuteBatch方法同时执行所有sql语句
            stmt.executeBatch();

        } catch (SQLException e) {
            e.printStackTrace();
        }

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来得晚一些也行

观众老爷,请赏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值