暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

springboot编程式事物

辉哥的菜 2021-09-06
1788

直接使用springboot操作下编程式事物的管理使用,主要是springboot很多配置和中间实现都省略了,一键注入就可以。

一、transactionTemplate方式

    @Component
    public class ProgramTransaction {
    Logger logger = LoggerFactory.getLogger(ProgramTransaction.class);
    @Autowired
    TransactionTemplate transactionTemplate;


    @Autowired
    UserDao userDao;


    public void TransactionTemplate(){
    //开启事务保存数据
    boolean result = transactionTemplate.execute(new TransactionCallback<Boolean>() {
    @Override
    public Boolean doInTransaction(TransactionStatus status) {
    try {
    programInsert1();
    } catch (Exception e) {
    //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 手动开启事务回滚
    status.setRollbackOnly();
    logger.error(e.getMessage(), e);
    return false;
    }
    return true;
    }
    });
    }
    // 使用方式1 直接
    public void programInsert1(){
    User user = new User();
    user.setName("programInsert1");
    user.setAge(34);
    user.setCountry("zouhui222");
    userDao.insert(user);
    }
    }

    这种方式直接就可以注入

       @Autowired
      TransactionTemplate transactionTemplate;

      是因为springboot在启动时候,自动会去实例化具有@configration注解的类,于是乎根据@Bean注解实例对应的对象放到spring容器中,这里面主要是因为有个@ConditionOnMissingBean注解会去容器中寻找是否有过实例化TransactionTemplate,如果没有,就直接实例化一个放到容器中,所以开始的时候注入这个没有问题。(这个依赖springboot启动时候注入的对象,在编译时期是不知道,也就是说在idea编辑器中不会提示它的实例化在哪里实现的,只有启动之后才会去绑定,图中跳转实例标识)

      @ConditionalOnMissingBean

      这个注入原理,后面有时间可以继续研究下,sprigboot自动化的东西,就是方便。

      tranactionTemplate通过调用execute方法匿名内部类,将需要事物的操作放在doInTransaction方法里面,通过手动捕获异常手动回滚。上图中,其实也可以看到这个transactionTemplate底层还是嵌套包裹了PlatformTransactionManager这个管理器的。当有事物的操作不放进try-catch里面时候,虽然程序遇到异常退出,但是事物也没有提交成功,自动回滚了。

      这样子虽然事物回滚了,但是对于程序来说不友好,所以还是建议自己的事物放进try-catch 里面,手动自己回滚,也更方便。

      二、transactionManager方式进行

        public void programInsert1(){
        User user = new User();
        user.setName("programInsert2");
        user.setAge(34);
        user.setCountry("zouhui222");
        userDao.insert(user);
        int a = 10 0;
        }
        @Autowired
        PlatformTransactionManager transactionManager;
        @Autowired
        TransactionDefinition transactionDefinition;
        public void transactionManager(){
        System.out.println("default isolation="+transactionDefinition.getIsolationLevel());
        System.out.println("default propagation="+transactionDefinition.getPropagationBehavior());


        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        System.out.println("rollbackonly="+transaction.isRollbackOnly());
        System.out.println("iscompleted="+transaction.isCompleted());
        try {
        programInsert1();
        transactionManager.commit(transaction);
        } catch (Exception e) {
        System.out.println("出现异常了 异常信息是:"+e.getMessage());
        System.out.println("iscompleted2="+transaction.isCompleted());
        transactionManager.rollback(transaction);
        }
        }

        手动提交事物手动自己捕获异常进行回滚,这个就是事物管理器了,也是上面一个方法的底层的调用。在springboot很多东西都有自定义的,默认的,比如TransactionDefinition PlatformTransactionManager都是springboot启动时候初始化出来的。可以看出来,这样子的默认的隔离级别是-1相当于走数据库自己的默认隔离级别了,mysql的inndb引擎就是读已提交级别了。传播属性是0,这个就是默认的required。

        spring的7中传播属性的枚举值类如下:

        对于编程式事物的事物传播性:

              @Autowired
          PlatformTransactionManager transactionManager;
          @Autowired
          TransactionDefinition transactionDefinition;
          public void transactionManager(){
          System.out.println("default isolation="+transactionDefinition.getIsolationLevel());
          System.out.println("default propagation="+transactionDefinition.getPropagationBehavior());
          TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
          System.out.println("rollbackonly="+transaction.isRollbackOnly());
          System.out.println("iscompleted="+transaction.isCompleted());
          try {
          transactionManager2();
          programInsert1();
          transactionManager.commit(transaction);
          } catch (Exception e) {
          System.out.println("出现异常了 异常信息是:"+e.getMessage());
          System.out.println("iscompleted2="+transaction.isCompleted());
          transactionManager.rollback(transaction);
          }
          }


          public void transactionManager2(){
          // 定义事务属性
          DefaultTransactionDefinition td = new DefaultTransactionDefinition();
          td.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
          td.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
          System.out.println("default isolation="+td.getIsolationLevel());
          System.out.println("default propagation="+td.getPropagationBehavior());
          TransactionStatus transaction = transactionManager.getTransaction(td);
          System.out.println("rollbackonly="+transaction.isRollbackOnly());
          System.out.println("iscompleted="+transaction.isCompleted());
          try {
          programInsert2();
          transactionManager.commit(transaction);
          } catch (Exception e) {
          System.out.println("出现异常了 异常信息是:"+e.getMessage());
          System.out.println("iscompleted2="+transaction.isCompleted());
          transactionManager.rollback(transaction);
          }
          }
          public void programInsert2(){
          User user = new User();
          user.setName("programInsert22");
          user.setAge(34);
          user.setCountry("zouhui222");
          userDao.insert(user);
          }

          transactionManager2定义了自己的事物属性:隔离级别、传播性是new_supports新开一个事物。transactionManager方法调用transactionManager2方法时候,两者的事物是相互独立不影响的,内部transactionManager2是正常提交,外层事物回滚。 通过该编程式事物可以发现,具有注解声明式的优点就是,可以自己类中使用事物传播属性,无需跨类或者自己注入自己代理的麻烦。

          三、事物底层源码解析初探

          首先从获取事物状态类这个开始:org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

          TransactionStatus transaction = transactionManager.getTransaction(td);

            protected Object doGetTransaction() {
                  //获取数据源事物对象  是数据源事物管理的一个静态内部类实例对象 继承了JdbcTransactionObjectSupport
            DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
            txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
            ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
            txObject.setConnectionHolder(conHolder, false);
            return txObject;
            }

            然后就进行事物的一些初始化动作,比如初始化默认事物状态类、获取连接池中、准备同步操作等

               //此处 针对嵌套事物时候的事物管理器中资源的挂起或者暂停 没有嵌套时候  
               // 相首次事物管理器的初始化 没有这个对象 所以传null
              AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources = this.suspend((Object)null);
              if (debugEnabled) {
              this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition);
              }


              try {
                          // 是否是新同步状态
              boolean newSynchronization = this.getTransactionSynchronization() != 2;
                              // 初始化默认的事物状态 根据自己自定义的事物属性或者默认自定义属性
              DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                              //初始化连接 设置隔离级别 设置自动提交为手动提交 设置事物连接状态true
              this.doBegin(transaction, (TransactionDefinition)definition);
                              //同步状态准备 做些全局属性的设置 当前事物隔离级别 、事物只读、事物是否启动等
                              // 主要是这个抽象类org.springframework.transaction.support.TransactionSynchronizationManager
                             this.prepareSynchronization(status, (TransactionDefinition)definition);
              return status;
              } catch (Error | RuntimeException var7) {
              this.resume((Object)null, suspendedResources);
              throw var7;
              }

              至此事物的一些初始化、准备工作搞定

              然后操作事物,进行事物的提交:

              提交事物主要走着个方法org.springframework.transaction.support.

              AbstractPlatformTransactionManager#processCommit

              最后提交事物给数据库:

              org.springframework.jdbc.datasource.DataSourceTransactionManage#doCommit;DataSourceTransactionManage 继承的是

              AbstractPlatformTransactionManager

              备注:源码初探,对于内部的一些定义还是不够了解深入,这次只是初识事物大致流程:连接池获取连接(也就是连接会话)-》设置隔离级别-》设置管理器全局属性-》提交事物(或者回滚事物)-》清空管理器当前连接的全局属性。

              文章转载自辉哥的菜,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论