13.7.2 JDBC的事务支持

13.7.2 JDBC的事务支持

JDBC连接也提供了事务支持,JDBC连接的事务支持由Connection提供, Connection默认打开自动提交,即关闭事务,在这种情况下,每条SQL语句一旦执行,便会立即提交到数据库,永久生效,无法对其进行回滚操作。
可以调用ConnectionsetAutoCommit()方法来关闭自动提交,开启事务,如下代码所示:
connection.setAutoCommit(false);
程序中还可调用Connection提供的getAutoCommit()方法来返回该连接的自动提交模式。
旦事务开始之后,程序可以像平常一样创建Statement对象,创建了Statement对象之后,可以执行任意多条DML语句,如下代码所示:

1
2
3
statement.executeUpdate(...);
statement.executeUpdate(...);
statement.executeUpdate(...);

上面这些SQL语句虽然被执行了,但这些SQL语句所做的修改不会生效,因为事务还没有结束。如果所有的SQL语句都执行成功,程序可以调用Connectioncommit()方法来提交事务,如下代码所示:
connection.commit();
如果任意一条SQL语句执行失败,则应该用Connectionrollback方法来回滚事务,如下代码所示:
connection.rollback();
实际上,当Connection遇到一个未处理的SQLException异常时,系统将会非正常退出,事务也会自动回滚。但如果程序捕获了该异常,则需要在异常处理块中显式地回滚事务.

实例 出现SQLException时,如果不捕获则系统自动回滚

下面程序示范了当程序出现未处理的SQLException异常时,系统将自动回滚事务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.sql.*;
import java.io.*;
import java.util.*;

public class TransactionTest
{
private String driver;
private String url;
private String user;
private String pass;
public void initParam(String paramFile) throws Exception
{
// 使用Properties类来加载属性文件
Properties props = new Properties();
props.load(new FileInputStream(paramFile));
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
pass = props.getProperty("pass");
}
public void insertInTransaction(String[] sqls) throws Exception
{
// 1.加载驱动
Class.forName(driver);
try (Connection conn = DriverManager.getConnection(url, user, pass))
{
// 关闭自动提交,开启事务
conn.setAutoCommit(false);
try (
// 使用Connection来创建一个Statment对象
Statement stmt = conn.createStatement())
{
// 循环多次执行SQL语句
for (String sql : sqls)
{
stmt.executeUpdate(sql);
}
}
// 提交事务
conn.commit();
}
}
public static void main(String[] args) throws Exception
{
TransactionTest tt = new TransactionTest();
tt.initParam("mysql.ini");
String[] sqls = new String[]
{"insert into student_table values(null , 'aaa' ,1)",
"insert into student_table values(null , 'bbb' ,1)",
"insert into student_table values(null , 'ccc' ,1)",
// 下面这条SQL语句将会违反外键约束,
// 因为teacher_table中没有ID为5的记录。
"insert into student_table values(null , 'ccc' ,5)" // ①
};
tt.insertInTransaction(sqls);
}
}

上面程序中的有开启事务、提交事务的代码,并没有回滚事务的代码。但当程序执行到第4条SQL语句(①处代码)时,这条语句将会引起外键约束异常,由于我们没有捕获处理该异常,所以事务会自动回滚

Connection对象中间的方法

Connection提供了两个方法来设置中间点。

  • Savepoint setSavepoint():在当前事务中创建一个未命名的中间点,并返回代表该中间点的Savepoint对象。
  • Savepoint setSavepoint(String name):在当前事务中创建一个具有指定名称的中间点,并返回代表该中间点的Savepoint对象。

通常来说,设置中间点时没有太大的必要指定名称,因为Connection回滚到指定中间点时,并不是根据名字回滚的,而是根据中间点对象回滚的, Connection提供了rollback(Savepoint savepoint)方法回滚到指定中间点。