在 java jdbc 中,使用 savepoint 实现事务回滚的核心步骤是:先通过 setsavepoint() 创建保存点,执行部分 sql 后若需局部回滚则调用 rollback(savepoint),最后用 releasesavepoint() 清理资源。默认情况下 jdbc 连接处于自动提交模式,必须先用 setautocommit(false) 关闭自动提交以开启事务控制。

如何创建和释放 Savepoint
创建保存点需要调用 Connection.setSavepoint(String name),该方法返回一个 Savepoint 对象实例。释放保存点则调用 Connection.releaseSavepoint(Savepoint sp)。如果在事务结束前未显式释放,JDBC 驱动通常会在 commit() 或 rollback() 时自动清理所有保存点,但显式释放是良好的编程习惯。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Savepoint;
import java.sql.Statement;
public class SavepointDemo {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String pass = "password";
try (Connection conn = DriverManager.getConnection(url, user, pass)) {
// 1. 关闭自动提交
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
// 2. 创建第一个保存点
Savepoint sp1 = conn.setSavepoint("sp1");
// 执行第一段操作
stmt.executeUpdate("INSERT INTO users (name) VALUES ('Alice')");
// 3. 创建第二个保存点
Savepoint sp2 = conn.setSavepoint("sp2");
// 执行第二段操作
stmt.executeUpdate("INSERT INTO users (name) VALUES ('Bob')");
// 模拟业务逻辑:如果 Bob 插入失败或不需要,可以回滚到 sp2
// conn.rollback(sp2);
// 4. 提交事务
conn.commit();
System.out.println("Transaction committed successfully.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
如何使用 rollback 回滚到指定 Savepoint
当部分操作出现异常或业务条件不满足时,调用 Connection.rollback(Savepoint sp) 可以将事务状态回退到该保存点创建时的状态。注意,回滚到保存点后,该保存点之后的其他保存点通常会失效(具体行为取决于 JDBC 驱动实现,标准行为是删除该保存点及之后的所有保存点)。回滚后,事务仍处于活动状态,可以继续执行后续 SQL 并提交。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Savepoint;
import java.sql.Statement;
public class RollbackToSavepointDemo {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String pass = "password";
try (Connection conn = DriverManager.getConnection(url, user, pass)) {
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
Savepoint sp1 = conn.setSavepoint("sp1");
stmt.executeUpdate("INSERT INTO users (name) VALUES ('Charlie')");
Savepoint sp2 = conn.setSavepoint("sp2");
stmt.executeUpdate("INSERT INTO users (name) VALUES ('David')");
// 假设 David 的插入导致数据不一致,我们决定回滚到 Charlie 之后
conn.rollback(sp2);
// 此时 Charlie 已存在,David 被移除
// 可以继续执行其他操作
stmt.executeUpdate("UPDATE users SET name='David_New' WHERE name='Charlie'");
conn.commit();
System.out.println("Rolled back to sp2 and continued.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
回滚到 Savepoint 后事务状态如何变化
调用 rollback(Savepoint) 后,事务并未结束,而是恢复到保存点创建时的数据库状态。此时连接仍然处于手动提交模式(autoCommit=false),你可以继续执行新的 SQL 语句。之前在该保存点之后创建的更高级别的保存点(即时间戳晚于当前保存点的)通常会被丢弃。最终仍需调用 commit() 才能将当前事务的所有更改持久化到数据库。如果在此过程中抛出异常且未被捕获,事务可能会进入不可恢复状态,建议在外层捕获异常并调用 conn.rollback() 进行全量回滚。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











