19、@Transactional的详解

一、不存在事务管理,发生异常不会回滚

 

二、@Transactional的事务传播级别:

事务传播级别

详解

REQUIRED

加入事务,默认值

SUPPORTS

存在就加入,不存在,非事务执行

MANDATORY

存在就加入,不存在抛异常

REQUIRES_NEW

重新新建事务,如果当前存在事务,则把当前事务挂起

NOT_SUPPORTED

非事务执行,如果当前存在事务,就把当前事务挂起

NEVER

不存在,非事务执行,如果当前存在事务,则抛出异常

NESTED

如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果不存在,则新建事务

 

三、@Transactional事务失效的情况:

@Transactional的本质是AOP

1、未配置事务管理器:

如果没有配置正确的事务管理器,或者事务管理器配置错误,@Transactional注解将会失效。确保在Spring配置文件中正确地配置了事务管理器。

2、方法未被Spring管理:

如果@Transactional注解的方法不是由Spring容器管理的(例如,通过new关键字手动创建对象),那么事务管理将不会生效。确保被注解的方法是Spring容器管理的Bean

3、方法被内部调用:

如果@Transactional注解的方法被同一个类中的另一个方法调用,而不是通过代理对象调用,那么事务将不会生效。这是因为Spring使用代理机制来实现事务,只有通过代理对象调用的方法才会被事务管理器拦截。

4、异常被捕获并处理

如果被@Transactional注解的方法内部发生异常,并且异常被方法内部捕获并处理,那么事务将不会回滚。通常情况下,事务应该在发生异常时回滚,以确保数据的一致性和完整性。

5、非public方法

如果@Transactional注解的方法是非public的,事务也可能会失效。在默认情况下,Spring只会代理public方法。

6、AOP顺序问题:

如果@Transactional注解的方法在AOP切面中的顺序不正确,也可能导致事务失效。确保@Transactional注解所在的切面在AOP代理链中的顺序正确

 

四、@Transactional在默认的事务传播级别下的方法调用:

A方法调B方法

1、A方法添加@Transactional注解,B方法未添加@Transactional注解:

(1)、A方法与B方法在同类中:

无论A方法还是B方法发生异常:AB方法均回滚

(2)、A方法与B方法不在同类中

无论A方法还是B方法发生异常:AB方法均回滚

2、A方法未添加@Transactional注解,B方法添加@Transactional注解:

(1)、A方法与B方法在同类中:

无论A方法还是B方法发生异常:AB方法均未回滚

(2)、A方法与B方法不在同类中

A方法发生异常:AB方法均未回滚

B方法发生异常:仅B方法回滚,A方法未回滚

3、总结:

(1)、如果A加@Transactional注解,不管是不是在一个类中,不管B加不加注解,AB都是在同一事务中;

(2)、如果A不加@Transactional注解,只有B加@Transactional注解,AB方法为同一类,事务失效;AB不同类,只有B有事务;

(3)、如果A不加@Transactional注解,B不加@Transactional注解,则没有事务;

注:

原因:A方法上有@Transactional注解,spring在管理的时候,会生成一个代理类,真正调用到A方法时,实际执行的是代理类里面的方法,该代理类里面的方法已经包括了B方法的调用,已经成为了一个方法。所以事务是有效的。

 

五、TransactionSynchronizationManager用于事务提交/回滚前后管理:

TransactionSynchronizationManager 是 Spring 框架中一个重要的类,用于管理事务同步资源。在使用 Spring 进行事务管理时,特别是在多线程环境或涉及多个资源(例如数据库连接、消息队列等)的复杂事务场景中,TransactionSynchronizationManager 可以帮助协调这些资源,使它们在一个事务上下文中得到正确的管理和处理。

主要功能:

  1. 事务资源绑定: 可以将特定的资源(如数据库连接、Hibernate会话等)绑定到当前事务上下文中。
  2. 事务同步: 提供在事务生命周期的各个阶段(如提交前、提交后、回滚前等)进行同步回调的机制
  3. 事务状态管理: 管理和检查当前线程是否处于事务上下文中,并获取相关事务状态信息。

操作示例:

    @Transactional
    public void TransactionManagerDemo(){
        // 执行数据库操作逻辑

        // 注册事务同步回调
        // 提供在事务生命周期的各个阶段(如提交前、提交后、回滚前等)进行同步回调的机制
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                // 在事务提交后执行的逻辑
                // 可以进行一些清理工作或发送通知
            }

            @Override
            public void afterCompletion(int status) {
                // 在事务完成后执行的逻辑
                // status表示事务的状态,可以根据不同状态执行不同的操作
                //————STATUS_COMMITTED:表示事务已成功提交。
                //————STATUS_ROLLED_BACK:表示事务已回滚。
                switch (status) {
                    case STATUS_COMMITTED:
                        System.out.println("Transaction committed successfully.");
                        // 执行事务提交后的逻辑
                        break;
                    case STATUS_ROLLED_BACK:
                        System.out.println("Transaction rolled back.");
                        // 执行事务回滚后的逻辑
                        break;
                    default:
                        throw new IllegalStateException("Unexpected transaction status: " + status);
                }
            }

            @Override
            public void beforeCommit(boolean readOnly) {
                // 在事务提交前执行的逻辑
                // readOnly表示事务是否为只读
                //readOnly = true:标记事务为只读事务。这意味着在这个事务中不应该进行任何更改数据库状态的操作 @Transactional(readOnly = true)
                //readOnly = false(默认值):标记事务为可读写事务,这意味着可以进行数据的插入、更新或删除操作 @Transactional
                if (readOnly) {
                    System.out.println("Before commit: This is a read-only transaction.");
                } else {
                    System.out.println("Before commit: This is a read-write transaction.");
                }
            }

            @Override
            public void beforeCompletion() {
                // 在事务完成前执行的逻辑
            }
        });
    }

 

六、分布式事务管理:

Spring框架提供@Transactional注解就能进行相应的事务控制,但是由于每个服务(单体)内部的数据一致性是由本地事务来保证的,对于全局的数据一致性却没办法保证,总而言之,一次业务操作需要跨多个数据源或需要跨多个服务进行远程调用,就会产生分布式事务问题。一般使用Seata默认的AT模式解决分布式事务,AT模式牺牲了一致性,保证了可用性,不过,它保证的是最终一致性

 

posted on 2024-06-25 00:29  爱文(Iven)  阅读(20)  评论(0编辑  收藏  举报

导航