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
}

相关推荐
Hello.Reader19 分钟前
Data Sink定义、参数与可落地示例
java·前端·网络
2401_837088501 小时前
stringRedisTemplate.opsForHash().entries
java·redis
lkbhua莱克瓦243 小时前
Java基础——集合进阶3
java·开发语言·笔记
蓝-萧3 小时前
使用Docker构建Node.js应用的详细指南
java·后端
多喝开水少熬夜3 小时前
Trie树相关算法题java实现
java·开发语言·算法
lkbhua莱克瓦244 小时前
Java基础——集合进阶用到的数据结构知识点1
java·数据结构·笔记·github
音符犹如代码5 小时前
Java并发List实战:CopyOnWriteArrayList原理与ArrayList常见面试题
java·开发语言·面试·list
代码or搬砖5 小时前
Docker 部署 Java 项目实践
java·docker·容器
又是忙碌的一天5 小时前
抽象类和接口
java·开发语言
August_._5 小时前
【MySQL】SQL语法详细总结
java·数据库·后端·sql·mysql·oracle