事务处理(Transaction Processing)是关系型数据库的一个重要概念。JDBC接口也支持应用程序向数据库提交事务。从数据库的角度看,事务处理的设计目的主要有两点:
一个事务中可能包含一条或者多条SQL语句。那么,JDBC接口如何将事务提交给数据库呢?我们将在本章中详细讲解JDBC事务处理的方法。
当我们创建出一个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);
}
}
}
在执行的过程中,如果出现了错误,开发人员还可以使用事务的回滚机制,帮助数据库恢复到之前的稳定状态。当执行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);
}
}
}
本章介绍了JDBC接口运行事务(Transactions)的基本使用方法。当禁止"自动提交时",JDBC接口会将多个SQL语句包装在一个事务中,在调用commit()方法时一次性的发送给数据库。在运行过程中如果出现任何错误,JDBC接口还支持回滚。开发人员可以取消所有尚未执行的SQL语句,也可以回滚到一个指定的Savepoint处。
注册用户登陆后可留言