09_database_07_jdbc-6

第八十二章 事务处理(Transaction Processing)

1. 简介

事务处理(Transaction Processing)是关系型数据库的一个重要概念。JDBC接口也支持应用程序向数据库提交事务。从数据库的角度看,事务处理的设计目的主要有两点:

  1. 事务处理提供了一种保持数据一致性(Data Consistency)的解决方案。当数据处理过程遇到问题或者异常时,数据库能保证数据处于一致的状态。开发人员能够控制流程继续进行,或者回滚到前一次稳定的、一致的状态。
  2. 事务处理提供了隔离性(Isolation)。当两个或者多个事务同时执行时,事务之间是不可见的(Invisible)。每一个事务的运行就像是她是唯一运行的事务一样。

一个事务中可能包含一条或者多条SQL语句。那么,JDBC接口如何将事务提交给数据库呢?我们将在本章中详细讲解JDBC事务处理的方法。

2. JDBC事务处理

2.1 基本使用方法

当我们创建出一个Connection对象后,它的初始状态处于"自动提交(Auto-commit Mode)"状态。在自动提交状态下,每当我们执行一条SQL语句,JDBC接口会将该语句立即发送给数据库执行。但是,在一些场景下,开发人员系统将多条SQL语句一起提交执行,而不是一条一条地提交执行。为了实现这一需求,我们可以关闭"自动提交"状态,然后调用commit()方法一次性提交所有的SQL语句。

Connection类提供了getAutoCommit()方法,该方法返回一个布尔值,用于检查当前Connection对象是否处于"自动提交"状态。setAutoCommit()方法可用于设置Connection对象的"自动提交"状态。如下代码示例展示了如何设置Connection对象的"自动提交"状态。在函数入口处,示例将保存Connection对象的当前状态;在方法返回时,恢复Connection对象的状态。

public class TransactionExample {
    public void process(Connection connection) throws SQLException {
        // 获取当前Connection对象的状态。
        boolean currentMode = connection.getAutoCommit();

        try {
            // 设置自动提交状态为false。
            connection.setAutoCommit(false);

            ...
            connection.commit();
        } finally {
            // 恢复到进入process()方法之前的状态。
            connection.setAutoCommit(currentMode);
        }
    }
}

在禁止"自动提交"后,开发人员就可以一次性发送多条SQL语句了。如下面的例子所示,process()方法一次性向student表中新增了两条学生记录。这里需要特别注意的是,如果不调用commit()方法,这些SQL语句是不会被执行的。

public class TransactionExample {
    public void process(Connection connection) throws SQLException {
        // 获取当前Connection对象的状态。
        boolean currentMode = connection.getAutoCommit();

        try {
            // 设置自动提交状态为false。
            connection.setAutoCommit(false);

            Statement stmt = connection.createStatement();
            stmt.execute("INSERT INTO student VALUES ('Adam', 22, 'Male');");
            stmt.execute("INSERT INTO student VALUES ('Amy', 23, 'Female');");
            
            connection.commit();
        } finally {
            // 恢复到进入process()方法之前的状态。
            connection.setAutoCommit(currentMode);
        }
    }
}

2.2 回滚(Rollback)

在执行的过程中,如果出现了错误,开发人员还可以使用事务的回滚机制,帮助数据库恢复到之前的稳定状态。当执行Connection对象的rollback()方法后,所有未执行的SQL语句都会被取消,不再执行。换句话说,数据库中的数据将会恢复到上次执行commit()方法时的状态。如下面的示例所示,当发生SQLException异常时,立即回滚。

public class TransactionExample {
    public void process(Connection connection) throws SQLException {
        // 获取当前Connection对象的状态。
        boolean currentMode = connection.getAutoCommit();

        try {
            // 设置自动提交状态为false。
            connection.setAutoCommit(false);

            Statement stmt = connection.createStatement();
            stmt.execute("INSERT INTO student VALUES ('Adam', 22, 'Male');");
            stmt.execute("INSERT INTO student VALUES ('Amy', 23, 'Female');");
            
            connection.commit();
        } catch (SQLException ex) {
            // 恢复到上次执行commit()方法时的状态。
            // 在本例中,上述的两个INSERT语句将不再执行。
            connection.rollback();
        } finally {
            // 恢复到进入process()方法之前的状态。
            connection.setAutoCommit(currentMode);
        }
    }
}

在调用回滚时,开发人员还可以选择回滚到一个指定的"状态"。这个"状态"被成为Savepoint。但是,在触发回滚之前,开发人员需要事先创建Savepoint。Connection类提供了setSavepoint()方法和releaseSavepoint()方法,用于创建和释放Savepoint。setSavepoint()方法返回一个Savepoint对象,将该对象传入rollback()方法时,数据库中的数据将会恢复到执行setSavepoint()方法时的状态。当将这个Savepoint对象传递给releaseSavepoint()方法后,该Savepoint对象会被释放,不能再被使用。

在下面的示例中,我们在方法的开始处创建了一个Savepoint,其对象名称为theSavepoint。在执行过程中,如果出现任何SQLException,我们调用rollback()方法恢复到theSavepoint处。在方法退出之前,我们还需要释放创建出的Savepoint对象。

public class TransactionExample {
    public void process(Connection connection) throws SQLException {
        boolean currentMode = connection.getAutoCommit();
        Savepoint theSavepoint = connection.setSavepoint();

        try {
            connection.setAutoCommit(false);

            Statement stmt = connection.createStatement();
            stmt.execute("INSERT INTO student VALUES ('Adam', 22, 'Male');");
            stmt.execute("INSERT INTO student VALUES ('Amy', 23, 'Female');");
            
            connection.commit();
        } catch (SQLException ex) {
            connection.rollback(theSavepoint);
        } finally {
            connection.setAutoCommit(currentMode);
            connection.releaseSavepoint(theSavepoint);
        }
    }
}

3. 小结

本章介绍了JDBC接口运行事务(Transactions)的基本使用方法。当禁止"自动提交时",JDBC接口会将多个SQL语句包装在一个事务中,在调用commit()方法时一次性的发送给数据库。在运行过程中如果出现任何错误,JDBC接口还支持回滚。开发人员可以取消所有尚未执行的SQL语句,也可以回滚到一个指定的Savepoint处。

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.