Java JDBC事务处理:手动提交与回滚实战

Chloe
Chloe
发布时间:2026-10-13| 4人浏览过
原创

JDBC连接默认处于自动提交模式,每个SQL语句执行后即写入数据库。为提升性能或确保业务流程的原子性,开发者通常需手动控制事务。本文阐述如何关闭自动提交,并通过Commit和Rollback机制处理成功提交与异常回滚的场景。

为何需要手动事务管理

在默认的自动提交模式下,任何一条SQL语句一旦完成便会立即生效。虽然这对简单应用足够,但在以下场景中必须关闭自动提交:

  • 提高性能:批量操作时减少与数据库的网络交互次数。
  • 保持业务完整性:将一组相关的SQL语句(如转账、订单创建)绑定为一个逻辑单元,要么全部成功,要么全部失败。
  • 分布式事务需求:涉及多个资源库的数据一致性保障。

核心操作步骤

第1步:关闭自动提交模式

要实现手动事务控制,首先需要将数据库连接设置为非自动提交状态。使用 setAutoCommit(boolean) 方法,传入 false 即可关闭自动提交。

conn.setAutoCommit(false);

此时,后续的SQL执行结果将暂存在内存中,不会真正写入数据库。

第2步:执行业务SQL并尝试提交

在同一个 try 块中执行一系列必要的SQL操作。如果所有步骤均无异常,调用 commit() 方法将挂起的更改永久应用到数据库。

// ... 执行 SQL ...
conn.commit();

第3步:异常捕获与回滚处理

若在执行过程中抛出 SQLException,说明某条语句失败或发生其他错误。此时应进入 catch 块,并调用 rollback() 取消当前事务内所有的更改,使数据库恢复到事务开始前的状态。

}catch(SQLException se){
  conn.rollback();
}

完整的事务控制代码实现

以下代码展示了一个完整的 JDBCExample.java 流程。它涵盖了从驱动加载、获取连接、设置事务属性、执行INSERT操作到最终清理资源的整个过程。

关键逻辑说明:

  1. 环境准备:使用 DriverManager.getConnection 获取连接,并立即调用 conn.setAutoCommit(false) 锁定事务控制权。
  2. 数据插入:连续插入两条员工记录(ID 106 和 107)。
  3. 验证输出:通过 printRs 辅助方法查询当前表内容,观察数据是否已刷新。
  4. 异常安全:finally 块负责关闭 ResultSet、Statement 和 Connection;catch (SQLException) 块负责触发 conn.rollback()。
import java.sql.*;

public class JDBCExample {
  // JDBC driver name and database URL
  static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; 
  static final String DB_URL = "jdbc:mysql://localhost/EMP";

  // Database credentials
  static final String USER = "username";
  static final String PASS = "password";
  
 public static void main(String[] args) {
  Connection conn = null;
  Statement stmt = null;
  try{
   //STEP 2: Register JDBC driver
   Class.forName("com.mysql.jdbc.Driver");

   //STEP 3: Open a connection
   System.out.println("Connecting to database...");
   conn = DriverManager.getConnection(DB_URL,USER,PASS);

   //STEP 4: Set auto commit as false.
   conn.setAutoCommit(false);

   //STEP 5: Execute a query to create statment with
   // required arguments for RS example.
   System.out.println("Creating statement...");
   stmt = conn.createStatement(
              ResultSet.TYPE_SCROLL_INSENSITIVE,
              ResultSet.CONCUR_UPDATABLE);
   
   //STEP 6: INSERT a row into Employees table
   System.out.println("Inserting one row....");
   String SQL = "INSERT INTO Employees " +
          "VALUES (106, 20, 'Rita', 'Tez')";
   stmt.executeUpdate(SQL); 

   //STEP 7: INSERT one more row into Employees table
   SQL = "INSERT INTO Employees " +
          "VALUES (107, 22, 'Sita', 'Singh')";
   stmt.executeUpdate(SQL);

   //STEP 8: Commit data here.
   System.out.println("Commiting data here....");
   conn.commit();
  
  //STEP 9: Now list all the available records.
   String sql = "SELECT id, first, last, age FROM Employees";
   ResultSet rs = stmt.executeQuery(sql);
   System.out.println("List result set for reference....");
   printRs(rs);

   //STEP 10: Clean-up environment
   rs.close();
   stmt.close();
   conn.close();
  }catch(SQLException se){
   //Handle errors for JDBC
   se.printStackTrace();
   // If there is an error then rollback the changes.
   System.out.println("Rolling back data here....");
  try{
  if(conn!=null)
      conn.rollback();
   }catch(SQLException se2){
     se2.printStackTrace();
   }//end try

  }catch(Exception e){
   //Handle errors for Class.forName
   e.printStackTrace();
  }finally{
   //finally block used to close resources
   try{
     if(stmt!=null)
      stmt.close();
   }catch(SQLException se2){
   }
   try{
     if(conn!=null)
      conn.close();
   }catch(SQLException se){
     se.printStackTrace();
   }
  }
  System.out.println("Goodbye!");
}//end main

  public static void printRs(ResultSet rs) throws SQLException{
   //Ensure we start with first row
   rs.beforeFirst();
   while(rs.next()){
     //Retrieve by column name
     int id = rs.getInt("id");
     int age = rs.getInt("age");
     String first = rs.getString("first");
     String last = rs.getString("last");

     //Display values
     System.out.print("ID: " + id);
     System.out.print(", Age: " + age);
     System.out.print(", First: " + first);
     System.out.println(", Last: " + last);
   }
   System.out.println();
  }
}

编译与运行

在命令行中使用 javac 编译源文件,然后运行 Java 类:

javac JDBCExample.java
java JDBCExample

程序正常运行后的典型输出如下(显示新插入的记录已成功持久化):

Connecting to database...
Creating statement...
Inserting one row....
Commiting data here....
List result set for reference....
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 28, First: Sumit, Last: Mittal
ID: 106, Age: 20, First: Rita, Last: Tez
ID: 107, Age: 22, First: Sita, Last: Singh
Goodbye!

上述输出表明两行新数据(106号和107号)被正确提交。如果在 STEP 7 故意制造语法错误(例如将 INSERT 拼写为 INSERTED),控制台将打印 “Rolling back data here....”,且数据库中不会出现这两行数据,从而保证了数据的一致性。

总结

JDBC中的事务管理主要依靠 setAutoCommit(false) 开启人工控制,随后配合 commit() 确认变更或 rollback() 撤销变更。这种方式特别适用于金融转账、多表关联更新等对数据准确性要求极高的场景。

以上就是Java JDBC事务提交的详细内容,更多关于Java数据库编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。