本文目录导读:

我为您准备了一个完整的JDBC事务管理案例,包含银行转账的经典场景,并提供两种实现方式。
数据库准备
-- 创建数据库
CREATE DATABASE bank_db;
USE bank_db;
-- 创建账户表
CREATE TABLE accounts (
id INT PRIMARY KEY AUTO_INCREMENT,
account_name VARCHAR(50) NOT NULL,
balance DECIMAL(10,2) NOT NULL
);
-- 插入测试数据
INSERT INTO accounts (account_name, balance) VALUES ('张三', 5000.00);
INSERT INTO accounts (account_name, balance) VALUES ('李四', 3000.00);
事务管理案例(转账操作)
方案1:基础版 - 手动事务管理
import java.sql.*;
public class TransactionDemo {
// 数据库连接参数
private static final String URL = "jdbc:mysql://localhost:3306/bank_db";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
public static void main(String[] args) {
transferFunds("张三", "李四", 1000.00);
}
/**
* 转账操作(含事务管理)
*/
public static void transferFunds(String fromAccount, String toAccount, double amount) {
Connection conn = null;
Statement stmt = null;
try {
// 1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取连接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
// 3. 关闭自动提交,开启事务
conn.setAutoCommit(false);
stmt = conn.createStatement();
// 4. 执行转账操作
// 4.1 扣款操作
String deductSQL = String.format(
"UPDATE accounts SET balance = balance - %.2f WHERE account_name = '%s'",
amount, fromAccount
);
int deductResult = stmt.executeUpdate(deductSQL);
// 检查扣款是否成功
if (deductResult == 0) {
throw new RuntimeException("转出账户不存在");
}
// 4.2 检查余额是否充足
String checkBalanceSQL = String.format(
"SELECT balance FROM accounts WHERE account_name = '%s'",
fromAccount
);
ResultSet rs = stmt.executeQuery(checkBalanceSQL);
if (rs.next()) {
double balance = rs.getDouble("balance");
if (balance < 0) {
throw new RuntimeException("余额不足,转账失败");
}
}
// 4.3 入账操作
String creditSQL = String.format(
"UPDATE accounts SET balance = balance + %.2f WHERE account_name = '%s'",
amount, toAccount
);
int creditResult = stmt.executeUpdate(creditSQL);
// 检查入账是否成功
if (creditResult == 0) {
throw new RuntimeException("转入账户不存在");
}
// 5. 所有操作成功,提交事务
conn.commit();
System.out.println("转账成功!");
} catch (Exception e) {
// 6. 出现异常,回滚事务
try {
if (conn != null) {
conn.rollback();
System.out.println("转账失败,事务已回滚!");
}
} catch (SQLException rollbackEx) {
rollbackEx.printStackTrace();
}
System.err.println("错误信息: " + e.getMessage());
} finally {
// 7. 释放资源
try {
if (stmt != null) stmt.close();
if (conn != null) {
conn.setAutoCommit(true); // 恢复自动提交
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
方案2:优化版 - 带事务边界控制
import java.sql.*;
public class TransactionDemo2 {
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/bank_db";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
public static void main(String[] args) {
// 测试用例
testTransactionSuccess(); // 测试成功场景
testTransactionFailure(); // 测试失败场景
testBalanceInsufficient(); // 测试余额不足场景
}
/**
* 转账服务类
*/
static class TransferService {
/**
* 执行转账(方法级事务控制)
*/
public void transfer(String fromAccount, String toAccount, double amount)
throws SQLException {
// 获取连接
try (Connection conn = getConnection()) {
// 开启事务
TransactionManager.beginTransaction(conn);
try {
// 执行转账逻辑
performTransfer(conn, fromAccount, toAccount, amount);
// 提交事务
TransactionManager.commit(conn);
System.out.println("转账成功:" + fromAccount + " -> " + toAccount + " 金额:" + amount);
} catch (Exception e) {
// 回滚事务
TransactionManager.rollback(conn);
System.err.println("转账失败,已回滚:" + e.getMessage());
throw new RuntimeException("转账失败", e);
}
}
}
/**
* 实际转账操作
*/
private void performTransfer(Connection conn, String fromAccount,
String toAccount, double amount) throws SQLException {
String sql = null;
try (PreparedStatement pstmt = conn.prepareStatement(
"UPDATE accounts SET balance = balance + ? WHERE account_name = ?")) {
// 1. 更新转出账户余额(扣款)
pstmt.setDouble(1, -amount);
pstmt.setString(2, fromAccount);
int row1 = pstmt.executeUpdate();
if (row1 != 1) {
throw new SQLException("转出账户不存在");
}
// 2. 检查转出账户余额是否足够
if (!isBalanceEnough(conn, fromAccount, amount)) {
throw new SQLException("余额不足");
}
// 3. 更新转入账户余额(入账)- 重新设置参数
pstmt.setDouble(1, amount);
pstmt.setString(2, toAccount);
int row2 = pstmt.executeUpdate();
if (row2 != 1) {
throw new SQLException("转入账户不存在");
}
}
}
/**
* 检查账户余额是否足够
*/
private boolean isBalanceEnough(Connection conn, String accountName,
double amount) throws SQLException {
String sql = "SELECT balance FROM accounts WHERE account_name = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, accountName);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return rs.getDouble("balance") >= amount;
}
return false;
}
}
}
}
/**
* 事务管理器 - 专门负责事务控制
*/
static class TransactionManager {
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void beginTransaction(Connection conn) throws SQLException {
conn.setAutoCommit(false);
}
public static void commit(Connection conn) throws SQLException {
conn.commit();
conn.setAutoCommit(true);
}
public static void rollback(Connection conn) throws SQLException {
conn.rollback();
conn.setAutoCommit(true);
}
}
/**
* 测试方法
*/
private static void testTransactionSuccess() {
System.out.println("=== 测试1:正常转账 ===");
TransferService service = new TransferService();
try {
service.transfer("张三", "李四", 500.00);
System.out.println("测试通过!");
} catch (Exception e) {
System.out.println("测试失败!");
}
}
private static void testTransactionFailure() {
System.out.println("\n=== 测试2:账户不存在 ===");
TransferService service = new TransferService();
try {
service.transfer("张三", "王五", 500.00); // 王五不存在
System.out.println("测试失败!");
} catch (Exception e) {
System.out.println("测试通过! 错误:" + e.getMessage());
// 验证数据一致性
checkDataConsistency();
}
}
private static void testBalanceInsufficient() {
System.out.println("\n=== 测试3:余额不足 ===");
TransferService service = new TransferService();
try {
service.transfer("张三", "李四", 50000.00); // 余额不足
System.out.println("测试失败!");
} catch (Exception e) {
System.out.println("测试通过! 错误:" + e.getMessage());
checkDataConsistency();
}
}
/**
* 检查数据一致性
*/
private static void checkDataConsistency() {
try (Connection conn = TransactionManager.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT account_name, balance FROM accounts")) {
System.out.println("当前账户余额:");
while (rs.next()) {
System.out.println(" " + rs.getString("account_name") +
":" + rs.getDouble("balance"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
方案3:最佳实践 - 通用事务模板
import java.sql.*;
/**
* 通用JDBC事务处理模板
*/
public abstract class JdbcTemplate {
private static final String URL = "jdbc:mysql://localhost:3306/bank_db";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
/**
* 在事务中执行操作
*/
public void executeInTransaction() throws SQLException {
Connection conn = null;
Savepoint savepoint = null;
try {
// 创建一个新连接
conn = DTBase.getConnection();
// 开启事务
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
// 设置保存点(可选)
savepoint = conn.setSavepoint("start");
// 执行具体操作
doInTransaction(conn);
// 提交事务
conn.commit();
} catch (SQLException e) {
if (conn != null) {
try {
// 回滚到保存点或回滚整个事务
if (savepoint != null) {
conn.rollback(savepoint);
} else {
conn.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
throw e;
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 抽象方法,由子类实现具体的业务逻辑
*/
protected abstract void doInTransaction(Connection conn) throws SQLException;
/**
* 数据库连接工厂类
*/
private static class DTBase {
public static Connection getConnection() throws SQLException {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (ClassNotFoundException e) {
throw new SQLException("数据库驱动加载失败", e);
}
}
}
}
/**
* 具体业务实现
*/
class TransferTask extends JdbcTemplate {
private String fromAccount;
private String toAccount;
private double amount;
public TransferTask(String from, String to, double amount) {
this.fromAccount = from;
this.toAccount = to;
this.amount = amount;
}
@Override
protected void doInTransaction(Connection conn) throws SQLException {
// 业务逻辑实现
String sql = "UPDATE accounts SET balance = balance + ? WHERE account_name = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 扣款
pstmt.setDouble(1, -amount);
pstmt.setString(2, fromAccount);
int count = pstmt.executeUpdate();
if (count == 0) {
throw new SQLException("转出账户不存在");
}
// 入账
pstmt.setDouble(1, amount);
pstmt.setString(2, toAccount);
count = pstmt.executeUpdate();
if (count == 0) {
throw new SQLException("转入账户不存在");
}
}
}
}
事务管理核心要点
事务特性(ACID)
- 原子性:事务中的所有操作要么全部成功,要么全部失败
- 一致性:事务执行前后,数据库完整性约束保持不变
- 隔离性:并发事务之间互不干扰
- 持久性:事务提交后,对数据库的改变是永久的
关键代码说明
// 开启事务
conn.setAutoCommit(false);
// 设置保存点
Savepoint sp = conn.setSavepoint("savepointName");
// 回滚到保存点
conn.rollback(sp);
// 提交事务
conn.commit();
// 回滚事务
conn.rollback();
事务隔离级别
// 设置隔离级别 conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
运行结果示例
=== 测试1:正常转账 ===
转账成功:张三 -> 李四 金额:500.0
测试通过!
=== 测试2:账户不存在 ===
转账失败,已回滚:转出账户不存在
测试通过! 当前账户余额:
张三:4830.0
李四:5170.0
=== 测试3:余额不足 ===
转账失败,已回滚:余额不足
测试通过! 当前账户余额:
张三:4830.0
李四:5170.0
注意事项
- 连接管理:使用try-with-resources自动管理资源
- 事务边界:明确事务的开始和结束位置
- 异常处理:捕获所有异常,确保事务正确回滚
- 性能考虑:事务尽量短,避免长时间占用连接
- 并发控制:合理设置事务隔离级别
- 日志记录:记录关键操作和异常信息
这个案例完整展示了JDBC事务管理的核心功能和最佳实践,可以根据实际需求选择合适的实现方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播