数据库事务
数据库事务是由数据库管理系统(DBMS)提供的、满足ACID特性的操作单元:
原子性(Atomicity):事务内所有操作要么全部成功,要么全部失败。
一致性(Consistency):事务执行前后,数据库状态保持一致。
隔离性(Isolation):并发事务互不干扰,通过隔离级别(如READ COMMITTED、REPEATABLE READ等)控制。
持久性(Durability):事务提交后,数据修改永久生效。
数据库通过 BEGIN TRANSACTION、COMMIT 和 ROLLBACK 管理事务,并依赖锁机制和日志(如redo log、binlog)实现回滚与恢复 。
Spring事务和数据库事务的关系
Spring事务是对数据库事务的封装与增强,其本质仍依赖底层数据库的事务能力:
若数据库不支持事务(如MySQL的MyISAM引擎),Spring事务无效 。
Spring通过事务管理器(如
DataSourceTransactionManager)获取数据库连接,并调用JDBC的commit()或rollback()完成事务操作 。Spring在数据库事务基础上,增加了传播行为、声明式配置和跨资源协调(如JTA)等高级特性 。
Spring事务的实现原理
Spring事务主要通过AOP动态代理实现:
在方法上标注
@Transactional后,Spring会为该Bean生成代理对象 。调用代理方法时,Spring先关闭自动提交(
setAutoCommit(false)),执行业务逻辑;若无异常则提交事务,否则回滚 。默认仅对
RuntimeException和Error回滚,可通过rollbackFor属性自定义 。支持编程式事务(手动控制
TransactionStatus)和声明式事务(注解驱动)两种方式 。事务传播机制(如
REQUIRED、REQUIRES_NEW)决定多个事务方法间的协作方式 。
Spring事务传播行为
Spring 事务传播行为定义了当一个带有事务的方法调用另一个事务方法时,事务应如何传播。Spring 在 TransactionDefinition 接口中定义了 7 种传播行为 :
PROPAGATION_REQUIRED(默认):如果当前存在事务,则加入该事务;否则创建一个新事务 。
PROPAGATION_REQUIRES_NEW:总是创建一个新事务;如果当前存在事务,则将其挂起 。
PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;否则以非事务方式执行 。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行;如果当前存在事务,则将其挂起 。
PROPAGATION_MANDATORY:必须在已有事务中执行,否则抛出异常 。
PROPAGATION_NEVER:必须以非事务方式执行,若存在事务则抛出异常 。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务中执行(依赖数据库 savepoint 支持);否则行为同 REQUIRED 。
这些传播行为通过 @Transactional(propagation = ...) 注解配置,用于精确控制事务边界与隔离性,满足不同业务场景需求 。
事务传播行为举例说明
Spring 事务的传播行为定义了当一个事务方法调用另一个事务方法时,事务应如何传播。Spring 提供了 7 种传播行为,可通过 @Transactional(propagation = Propagation.XXX) 配置。以下是各项行为的代码示例说明:
PROPAGATION_REQUIRED(默认)
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
dao.insertA();
methodB(); // 与 methodA 共享同一事务
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() { dao.insertB(); }若 methodB 抛异常,methodA 和 B 均回滚 。
若当前存在事务,则加入;否则新建事务。
PROPAGATION_REQUIRES_NEW
@Transactional
public void methodA() {
dao.insertA();
methodB(); // 挂起 A 的事务,B 独立提交
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() { dao.insertB(); }即使 methodA 回滚,methodB 的数据仍保留 。
总是新建事务,挂起当前事务(如有)。
PROPAGATION_SUPPORTS
public void methodA() { // 无事务
methodB(); // 非事务方式执行
}
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() { dao.insertB(); }methodB 不会开启新事务 。
有事务则加入,无则非事务执行。
PROPAGATION_NOT_SUPPORTED
@Transactional
public void methodA() {
methodB(); // 挂起 A 的事务,B 非事务执行
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() { dao.insertB(); }methodB 的操作不受 methodA 事务控制 。
以非事务方式执行,挂起当前事务。
PROPAGATION_MANDATORY
public void methodA() { // 无事务
methodB(); // 抛出 IllegalTransactionStateException
}
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() { dao.insertB(); }必须在已有事务中执行,否则抛异常。
PROPAGATION_NEVER
@Transactional
public void methodA() {
methodB(); // 抛异常
}
@Transactional(propagation = Propagation.NEVER)
public void methodB() { dao.insertB(); }必须非事务执行,若存在事务则抛异常。
PROPAGATION_NESTED
@Transactional
public void methodA() {
dao.insertA();
methodB(); // 创建保存点
// 若 methodB 异常,仅回滚 B;若 A 异常,全部回滚
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() { dao.insertB(); }依赖数据库对 savepoint 的支持 。
若存在事务,则在嵌套事务(基于保存点)中执行。
注意:以上行为均基于 Spring AOP 代理机制,且要求方法为 public 并通过 Spring 容器调用 。
Spring事务最佳实践
避免在事务方法内捕获异常而不抛出:否则Spring无法触发回滚 。
合理设置
rollbackFor:若需对检查型异常回滚,应显式配置 。慎用
REQUIRES_NEW:可能导致事务悬挂或数据不一致。注意事务边界:事务方法应聚焦于数据库操作,避免包含远程调用、耗时IO等非事务逻辑。
隔离级别以Spring配置为准:若数据库不支持指定级别,则效果由数据库决定 。
不要依赖事务保证业务逻辑正确性:事务仅回滚数据库操作,已执行的非DB操作(如发消息、写文件)不会回滚 。
评论区