有关事务的相关知识点可阅读文章:SQL完整性、多表查询及事务
JDBC中的事务
事务能够控制是否和何时更改应用于数据库,将单个SQL语句或一组SQL语句视为一个逻辑单元,如果任何语句失败,则整个事务将失败
JDBC驱动程序默认使用自动提交模式,每个SQL语句在完成后都会提交到数据库
- 启用手动事务支持:
使用Connection对象的setAutoCommit()方法
如果将boolean false传递给setAutoCommit()则关闭自动提交,可以通过传递布尔值true重新打开它
事务的提交和回滚
事务默认使用自动提交模式
启用手动事务支持:
- 将false传递给setAutoCommit()关闭自动提交
connection.setAutoCommit(false);//关闭自动提交事务
- 完成更改后,在连接对象上调用commit()方法提交事务
connection.commit();//手动提交事务
- 如果不提交事务或者发生错误,则进行回滚更新
connection.rollback();
代码示例:
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
//1加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
connection = DriverManager.getConnection(url, userName, passWord);
connection.setAutoCommit(false);//关闭自动提交事务
//3定义sql,创建状态通道(进行sql语句的发送)
statement = connection.createStatement();
//4执行增删改查
int result = statement.executeUpdate("insert into student values(9,'哈哈','3')");
connection.commit();//手动提交事务
//返回结果为受影响的行数
if(result > 0){
System.out.println("执行成功");
}else{
System.out.println("执行失败");
}
} catch (Exception e) {
e.printStackTrace();
try {
connection.rollback();//如果出现异常,则回滚
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally {
try {
//5关闭资源
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}//end finally
}
某些业务逻辑需要同时成功or同时失败,因此需要设置手动提交事务,此时某些业务发生异常后不能进行事务提交,这是事务的意义
该事务案例可阅读文章:JDBC事务案例——转账
保存点Savepoints
Savepoint接口提供了额外的事务控制
设置保存点时,可以在事务中定义逻辑回滚点,如果发生异常,则可以使用回滚方法来撤消所有更改或仅保存在保存点之前所做的更改
Connection对象有两种新的方法管理保存点 :
方法 | 描述 |
---|---|
setSavepoint(String savepointName) | 定义新的保存点,返回一个Savepoint对象 |
releaseSavepoint(Savepoint savepointName) | 删除保存点,tips:需要一个Savepoint对象作为参数,此对象通常是由setSavepoint()方法生成的保存点 |
代码示例:
在执行insert操作之后添加会抛出异常的语句System.out.println(1/0);使事务进行catch中的rollback操作,由于事务具有原子性,因此result1和result2都不执行,代码如下
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
Savepoint savepoint1 =null;
try {
//1加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
connection = DriverManager.getConnection(url, userName, passWord);
connection.setAutoCommit(false);//关闭自动提交事务
//3定义sql,创建状态通道(进行sql语句的发送)
statement = connection.createStatement();
//4执行增删改查
int result1 = statement.executeUpdate("insert into student values(10,'保存点1','3')");
/*
savepoint1 = connection.setSavepoint("Savepoint1");
*/
int result2 = statement.executeUpdate("insert into student values(11,'保存点2','3')");
System.out.println(1/0);//通过异常让事务进行回滚,由于result1和result2属于同一个事务,因此都不执行
connection.commit();//手动提交事务
//返回结果为受影响的行数
if(result1 > 0){
System.out.println("执行成功");
}else{
System.out.println("执行失败");
}
} catch (Exception e) {
e.printStackTrace();
try {
connection.rollback();
/*
connection.rollback(savepoint1);//回滚到保存点
connection.commit();//提交事务,即保存点之前的事务
*/
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally {
try {
//5关闭资源
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}//end finally
}//end main
保存点可以在事务中定义回滚点,如果发生异常,使用回滚方法来保存在保存点之前所做的更改,即上述代码/**/注释部分
- 在result1和result2之间定义回滚点savepoint1
savepoint1 = connection.setSavepoint("Savepoint1");
- 异常处理的catch中设置回滚到保存点,并提交保存点之前的事务
//connection.rollback();
connection.rollback(savepoint1);//回滚到保存点
connection.commit();//提交事务,即保存点之前的事务
此时运行时虽然会抛出异常,但是成功提交保存点之前的事务,即result1