本文目录导读:

- 基于JDBC的简单回滚(最基础)
- Spring JDBC 模板的回滚(Spring框架)
- 基于Spring + MyBatis的完整案例
- 编程式事务管理(Spring)
- 事务传播行为示例
- 配置文件示例(application.yml)
- 数据库表结构
在Java中实现数据库回滚主要有几种方式,我将通过几个典型案例来展示。
基于JDBC的简单回滚(最基础)
import java.sql.*;
public class JDBCRollbackExample {
public static void main(String[] args) {
Connection conn = null;
try {
// 1. 获取数据库连接
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test",
"root",
"password"
);
// 2. 关闭自动提交,开启事务
conn.setAutoCommit(false);
// 3. 执行多条SQL语句
Statement stmt = conn.createStatement();
// 模拟两个操作
stmt.executeUpdate("INSERT INTO users (name, age) VALUES ('张三', 25)");
// 故意制造一个错误
int result = 1 / 0; // 这里会抛出异常
stmt.executeUpdate("INSERT INTO users (name, age) VALUES ('李四', 30)");
// 4. 所有操作成功,提交事务
conn.commit();
System.out.println("事务提交成功!");
} catch (Exception e) {
// 5. 发生异常,回滚事务
if (conn != null) {
try {
conn.rollback();
System.out.println("事务已回滚!");
} catch (SQLException ex) {
ex.printStackTrace();
}
}
e.printStackTrace();
} finally {
// 6. 关闭连接
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
Spring JDBC 模板的回滚(Spring框架)
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
@Resource
private JdbcTemplate jdbcTemplate;
@Transactional(rollbackFor = Exception.class)
public void transferMoney(Long fromUserId, Long toUserId, Double amount) {
// 1. 扣款操作
String deductSql = "UPDATE accounts SET balance = balance - ? WHERE user_id = ?";
jdbcTemplate.update(deductSql, amount, fromUserId);
// 模拟一个异常
if (fromUserId.equals(toUserId)) {
throw new RuntimeException("不能转账给自己!");
}
// 2. 加款操作
String addSql = "UPDATE accounts SET balance = balance + ? WHERE user_id = ?";
jdbcTemplate.update(addSql, amount, toUserId);
// 如果以上任何一步出错,整个事务都会回滚
System.out.println("转账成功!");
}
}
基于Spring + MyBatis的完整案例
// 实体类
public class Account {
private Long id;
private String name;
private Double balance;
// getter和setter方法
}
// Mapper接口
@Mapper
public interface AccountMapper {
@Update("UPDATE account SET balance = balance - #{amount} WHERE id = #{id}")
int deductBalance(@Param("id") Long id, @Param("amount") Double amount);
@Update("UPDATE account SET balance = balance + #{amount} WHERE id = #{id}")
int addBalance(@Param("id") Long id, @Param("amount") Double amount);
}
// Service实现类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void transfer(Long fromId, Long toId, Double amount) {
// 1. 校验余额是否充足
Account fromAccount = accountMapper.findById(fromId);
if (fromAccount.getBalance() < amount) {
throw new BusinessException("余额不足");
}
// 2. 扣款
int rows = accountMapper.deductBalance(fromId, amount);
if (rows == 0) {
throw new BusinessException("扣款失败");
}
// 模拟一个运行时异常
if (amount <= 0) {
throw new IllegalArgumentException("转账金额必须大于0");
}
// 3. 加款
rows = accountMapper.addBalance(toId, amount);
if (rows == 0) {
throw new BusinessException("加款失败");
}
}
}
// 自定义业务异常
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
}
编程式事务管理(Spring)
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class ProgrammaticTransactionService {
@Autowired
private PlatformTransactionManager transactionManager;
public void businessLogic() {
// 创建事务定义
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 开启事务
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务逻辑
// ... 执行数据库操作
// 提交事务
transactionManager.commit(status);
System.out.println("事务提交成功");
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
System.out.println("事务回滚成功");
e.printStackTrace();
}
}
}
事务传播行为示例
@Service
public class TransactionPropagationExample {
@Autowired
private MethodA methodA;
@Service
public static class MethodA {
@Transactional
public void methodA() {
// 数据库操作1
insertData("A");
try {
methodB(); // 调用方法B
} catch (Exception e) {
// 即使方法B失败了,方法A的代码不会受影响(如果B使用REQUIRES_NEW)
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW) // 开启新事务
public void methodB() {
// 数据库操作2
insertData("B");
// 这里抛异常,只回滚方法B的事务
if (true) {
throw new RuntimeException("方法B的异常");
}
}
}
}
配置文件示例(application.yml)
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
# 事务管理器配置
jpa:
hibernate:
ddl-auto: create-drop
# 事务配置
transaction:
default-timeout: 30
# MyBatis配置
mybatis:
configuration:
map-underscore-to-camel-case: true
数据库表结构
-- 创建账户表
CREATE TABLE account (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
balance DECIMAL(10,2) NOT NULL DEFAULT 0
);
-- 创建用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT NOT NULL
);
-- 创建账户明细表
CREATE TABLE account_transaction_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
from_account_id BIGINT NOT NULL,
to_account_id BIGINT NOT NULL,
amount DECIMAL(10,2),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-
JDBC层面:通过
conn.setAutoCommit(false)关闭自动提交,手动控制commit()和rollback() -
Spring注解方式:
@Transactional是最常用的方式rollbackFor指定哪些异常触发回滚propagation设置事务传播行为
-
事务特性:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
-
最佳实践:
- 尽量使用声明式事务(
@Transactional) - 异常要设置正确的
rollbackFor - 避免长事务
- 注意事务的隔离级别
- 尽量使用声明式事务(
这个案例涵盖了从基础的JDBC到Spring框架的各种回滚实现方式,可以根据项目需求选择合适的方式。