Spring事务

Spring事务大致流程

当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事 务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。

Spring事务的代理对象执行某个方法时的步骤:

  1. 判断当前执行的方法是否存在@Transactional注解
  2. 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
  3. 修改数据库连接的autocommit为false
  4. 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
  5. 执行完了之后如果没有出现异常,则提交,否则回滚 Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判 断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效
  6. 如果没有抛异常,则提交
  7. 如果抛了异常,则回滚

Spring事务传播机制

Spring事务大致流程

当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事 务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。

Spring事务的代理对象执行某个方法时的步骤:

  1. 判断当前执行的方法是否存在@Transactional注解
  2. 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
  3. 修改数据库连接的autocommit为false
  4. 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
  5. 执行完了之后如果没有出现异常,则提交,否则回滚 Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判 断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效
  6. 如果没有抛异常,则提交
  7. 如果抛了异常,则回滚

Spring事务传播机制

默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事 务中执行。

也可以手动设置为REQUIRED_NEW,将ThreadLocal中已有的conn移除,并放入一个挂起对象资源中。

场景一:

typescript 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional 
      public void a() { 
         // sql 
         userService.b(); 
      }
​
      @Transactional 
      public void b() { 
          // sql
      } 
} 

执行流程:

  1. 事务管理器创建数据库连接conn
  1. 将autocommit设置为false
  1. 将数据库连接放置到ThreadLocal中
  1. 执行a中的sql
  1. 执行b中的sql
  1. 执行conn的方法commit提交

场景二:

typescript 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional
      public void a() { 
         // sql 
         userService.b(); 
      }
​
      @Transactional 
      public void b() { 
          // sql
          int i = 100/0;
      } 
}

执行流程:

1、事务管理器建立数据库连接conn

2、将autocommit设置成false

3、将conn放入ThreadLocal

4、执行方法a中的sql

5、执行方法b中的sql

6、异常报错

7、执行conn中的rollback回滚方法,两个方法中的事务都会回滚掉

场景三:

typescript 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional
      public void a() { 
         // sql 
         userService.b(); 
         int i = 100/0;
      }
​
      @Transactional 
      public void b() { 
          // sql
      } 
}

执行流程:

1、事务管理器创建一个数据库连接conn

2、将autocommit设置为false

3、执行方法a中的sql

4、执行b中的方法

5、报异常

6、调用conn的rollback方法,两个方法的事务都会回滚

场景四:

typescript 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional
      public void a() { 
         // sql 
         userService.b(); 
​
      }
​
      @Transactional(Propagation=propagation.REQUIRES_NEW)
      public void b() { 
          // sql
      } 
}

执行流程:

1、事务管理器创建一个数据库连接conn

2、将autocommit设置为false

3、执行方法a中的sql

4、将ThreadLocal中a方法的conn移除,挂起到资源对象中

5、事务管理器创建一个数据库连接conn2(方法b的)

6、 执行b方法的sql

7、conn2调用commit方法提交事务

8、然后再把挂起资源对象中的coon(方法a的)恢复到ThreadLocal中

9、a执行完后,conn调用commit方法提交事务

场景五:

java 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional
      public void a() { 
         // sql 
         userService.b(); 
         int i = 100/0;
​
      }
​
      @Transactional(Propagation=propagation.REQUIRES_NEW)
      public void b() { 
          // sql
      } 
}

​执行流程:

1、事务管理器创建一个数据库连接conn

2、将autocommit设置为false

3、执行方法a中的sql

4、将conn从ThreadLocal中移除,存入挂起资源中

5、事务管理器新建一个conn2存放到ThreadLocal中

6、报异常

7、两个事务都得回滚(因为事务a中调用了事务b,事务a报异常回滚了,事务b也得回滚)

场景六:

java 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional
      public void a() { 
         // sql 
         userService.b(); 
​
      }
​
      @Transactional(Propagation=propagation.REQUIRES_NEW)
      public void b() { 
          // sql
          int i = 100/0;
      } 
}

执行流程:

1、事务管理器创建一个数据库连接conn

2、设置autocommit为false

3、执行方法a的sql

4、将conn从ThreadLocal中移除,并存入挂起资源对象

5、方法b新建一个连接conn2

6、异常报错

7、conn2调用rollback回滚事务

8、继续抛异常,对于test()方法而言,它会接收到一个异常,然后抛出

9、执行conn的rollback()方法进行回滚,最终还是两个方法中的sql都回滚了

Spring事务强制回滚

正常情况下,a()调用b()方法时,如果b()方法抛了异常,但是在a()方法捕获了,那么a()的事务还是会正常提交的,但是你b()方法都执行异常并抛出了,还继续执行干什么,所以我们通常可以有在a()方法中捕获异常并将异常友好的提示出去:

java 复制代码
@Component 
public class UserService { 
​
      @Autowired 
      private UserService userService; 
​
      @Transactional
      public void a() { 
         // sql 
         try{
         userService.b(); 
         }catch{
            // 构造友好的错误信息返回
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
         }
​
      }
​
      @Transactional(Propagation=propagation.REQUIRES_NEW)
      public void b() throws Exception{ 
          // sql
          int i = 100/0;
      } 
}

TransactionSynchronization

Spring事务有可能会 提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监 听当前Spring事务所处于的状态。

typescript 复制代码
@Component 
public class UserService { 
      @Autowired 
      private JdbcTemplate jdbcTemplate; 
      @Autowired 
      private UserService userService; 

      @Transactional 
      public void test(){ 
           TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { 
        @Override 
        public void suspend() { 
          System.out.println("test被挂起了"); } 

        @Override 
        public void resume() { 
          System.out.println("test被恢复了"); } 

        @Override 
        public void beforeCommit(boolean readOnly) { 
          System.out.println("test准备要提交了"); } 

        @Override 
        public void beforeCompletion() { 
          System.out.println("test准备要提交或回滚了"); } 

        @Override 
        public void afterCommit() { 
          System.out.println("test提交成功了"); } 

        @Override 
        public void afterCompletion(int status) { 
          System.out.println("test提交或回滚成功了");}}; 
        //方法test()的sql
}

相关推荐
苹果醋329 分钟前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
Hello.Reader1 小时前
深入解析 Apache APISIX
java·apache
菠萝蚊鸭1 小时前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
007php0071 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
∝请叫*我简单先生1 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
ssr——ssss2 小时前
SSM-期末项目 - 基于SSM的宠物信息管理系统
java·ssm
一棵星2 小时前
Java模拟Mqtt客户端连接Mqtt Broker
java·开发语言
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#
zquwei2 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring