源码入手学习 Spring 事务管理机制

Spring 框架的事务管理是企业级应用开发的核心功能之一,它通过统一的事务抽象层简化了不同数据访问技术(如 JDBC、Hibernate、JPA 等)的事务管理。以下是 Spring 事务的核心要点:

1. 事务核心接口组件

1.1 PlatformTransactionManager

事务管理的核心接口

public interface PlatformTransactionManager extends TransactionManager {  
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;  

    void commit(TransactionStatus status) throws TransactionException;  

    void rollback(TransactionStatus status) throws TransactionException;  
}

针对不同的数据源有不同具体实现(策略模式)

重要实现类:DataSourceTransactionManager

1.2 TransactionDefinition

  • 该接口中定义了事务的传播行为隔离级别超时时间只读模式等属性

1.2.1 传播行为详解

这一部分只看定义会有些抽象,可以在第三部分大小事务处理中加深理解

  • 常用传播行为(Propagation 事务边界):
    • REQUIRED(默认):如果当前存在事务,则加入;否则新建事务
    • REQUIRES_NEW:始终新建事务,挂起当前事务(如果存在)
    • SUPPORTS:如果有事务则加入,否则以非事务方式运行
    • NOT_SUPPORTED:以非事务方式运行,挂起当前事务(如果存在)
    • MANDATORY:必须存在事务,否则抛出异常
    • NEVER:必须在非事务环境下运行,否则抛出异常

其中 TransactionTemplate 编程式事务就是其实现类,在构造方法中可以通过TransactionDefinition 提供这些事务属性。

1.3 TransactionOperations

如上图所示,是 TransactionTemplate 的另一个接口,提供 execute 方法来执行事务操作。通过 TransactionCallback 回调来执行实际的业务逻辑,并根据异常或事务状态来决定是否提交或回滚事务。

2. 事务管理方式

2.1 编程式事务

  • 通过 TransactionTemplate手动控制事务边界
    • 在实例构造时,通过 TransactionDefinition 传入边界属性
    • 在代码中通过 try catch 灵活声明触发回滚的异常
  • 示例代码:
@Autowired
private TransactionTemplate transactionTemplate;

public void doSomething() {
    transactionTemplate.execute(status -> {
        try {
            // 业务逻辑
            return result;
        } catch (Exception e) {
            status.setRollbackOnly(); // 标记回滚
            return null;
        }
    });
}

2.2 声明式事务

  • 通过 @Transactional 注解或 XML 配置声明事务行为
  • 基于 AOP 实现,对业务代码无侵入
  • 需要注意只能用于 public 方法
  • 示例:
@Service
public class UserService {

    @Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.READ_COMMITTED,
        timeout = 30,
        rollbackFor = {SQLException.class}
    )
    public void updateUser(User user) {
            // 数据库操作
    }
}

2.2.1 @Transactional 注解详解

// 类/接口上,方法上
@Target({ElementType.TYPE, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Inherited  
@Documented  
public @interface Transactional {  

    // 指定 Bean 名称,多用于多数据源的场景的依赖倒置
    @AliasFor("transactionManager")  
    String value() default "";  
    @AliasFor("value")  
    String transactionManager() default "";  
    String[] label() default {};  

    // 事务传播行为,控制事务的边界逻辑
    Propagation propagation() default Propagation.REQUIRED;  

    // 事务隔离级别,同 innoDB 的四个隔离级别 (默认为数据库默认级别)
    Isolation isolation() default Isolation.DEFAULT;  

    // 事务超时时间
    int timeout() default -1;  

    String timeoutString() default "";  

    boolean readOnly() default false;  

    // 会触发回滚的异常类型,默认仅回滚 `RuntimeException` 和 `Error`(非检查异常)
    Class<? extends Throwable>[] rollbackFor() default {};  

    String[] rollbackForClassName() default {};  

    // 不会触发回滚的异常类型
    Class<? extends Throwable>[] noRollbackFor() default {};  

    String[] noRollbackForClassName() default {};  
}

2.2.2 声明式事务实现原理

  1. 代理机制:通过 AOP(动态代理) 对 @Transactional 注解的方法进行增强
  2. 事务拦截器TransactionInterceptor 负责事务的开启、提交和回滚
  3. 代理类型
    • 如果目标类实现接口,默认使用 JDK 动态代理
    • 否则使用 CGLIB 代理

3. 事务场景

3.1 大小事务的处理

1. 场景明晰

  • 父事务(大事务):通常是一个外层事务,它控制着多个业务操作,可能涉及多个方法调用。父事务负责整个操作的一致性。如果父事务中有一个子事务失败,父事务可以决定是否回滚整个事务。
  • 子事务(小事务)**:是父事务内部执行的子操作,它们可以作为嵌套事务或独立事务存在。子事务可以通过不同的传播行为与父事务相互作用,甚至在子事务回滚时,不影响父事务的状态。

一个例子:在一个大型的金融应用中,可能有多个步骤需要执行,如订单创建、支付、发货等。每个步骤都可以看作一个子事务,而整个订单的创建、支付流程可以看作一个父事务。在这种情况下,如果子事务失败,整个父事务也会失败(除非设置了 REQUIRES_NEW 或 NESTED 等传播行为)。

@Transactional
public void parentTransaction() {
    // 父事务逻辑
    childTransaction(); // 调用子事务
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void childTransaction() {
    // 子事务逻辑
    // 即使子事务失败,父事务依然可以继续
    throw new RuntimeException("子事务失败");
}

2. 传播行为如何进行大小事务的回滚处理

Spring 事务是通过不同的传播行为(propagation)来区分对大小事务的不同处理的。基于这个大小事务的场景,会对下面三个传播行为有更好的认识:

  • REQUIRED(默认传播行为):如果当前存在事务,则加入当前事务;如果没有事务,则创建一个新的事务。此时,子事务的回滚会导致整个父事务回滚,子事务和父事务是同一个事务
  • NESTED:如果当前有事务,则在当前事务中嵌套一个事务,并且子事务的回滚不会影响父事务的提交。只有子事务的异常抛出并导致事务回滚,才会使得父事务回滚。
  • REQUIRES_NEW:总是创建一个新的事务,并挂起当前事务。无论父事务是否成功,子事务的提交或回滚都不会影响父事务。

3. 总结

  • REQUIRED:子事务回滚时,父事务也回滚(同一个事务)。
  • REQUIRES_NEW:子事务回滚时,不影响父事务,父事务继续执行。
  • NESTED:子事务回滚时,只有子事务会回滚,父事务不会受到影响,除非父事务也发生回滚。

因此,在处理大小事务回滚时,需要根据具体的业务需求来选择合适的事务传播行为。如果需要精细的事务控制,可以选择 NESTED 或 REQUIRES_NEW,确保子事务的失败不会影响父事务的执行。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇