项目开发-iBatis事务源码之事务提交和回滚

接上篇继续事务的提交和结束流程如下。

commitTransaction

SqlMapClientImpl的commitTransaction操作,类似startTransaction,是最终由SqlMapExecutorDelege的commitTransaction完成的。

  /**
   * Commit the transaction on a session
   *
   * @param sessionScope - the session
   * @throws SQLException - if the transaction could not be committed
   */
  public void commitTransaction(SessionScope sessionScope) throws SQLException {
    try {
      // Auto batch execution
      if (sessionScope.isInBatch()) {
        executeBatch(sessionScope);
      }
      sqlExecutor.cleanup(sessionScope);
      txManager.commit(sessionScope);
    } catch (TransactionException e) {
      throw new NestedSQLException("Could not commit transaction.  Cause: " + e, e);
    }
  }

TransactionManager的commit

  public void commit(SessionScope sessionScope) throws SQLException, TransactionException {
    Transaction trans = sessionScope.getTransaction();
    TransactionState state = sessionScope.getTransactionState();
    if (state == TransactionState.STATE_USER_PROVIDED) {
      throw new TransactionException("TransactionManager could not commit.  " +
          "A user provided connection is currently being used by this session.  " +
          "You must call the commit() method of the Connection directly.  " +
          "The calling .setUserConnection (null) will clear the user provided transaction.");
    } else if (state != TransactionState.STATE_STARTED && state != TransactionState.STATE_COMMITTED ) {
      throw new TransactionException("TransactionManager could not commit.  No transaction is started.");
    }
    System.out.println("hello:"+(sessionScope.isCommitRequired() || config.isForceCommit()));
    if (sessionScope.isCommitRequired() || config.isForceCommit()) {
      trans.commit();
      sessionScope.setCommitRequired(false);
    }
    sessionScope.setTransactionState(TransactionState.STATE_COMMITTED);
  }

Transaction的commit

  public void commit() throws SQLException, TransactionException {
    if (connection != null) {
      connection.commit();
    }
  }

事务提交操作执行完成后,事务状态被置为提交状态,有增删改操作时,commitRequired标识为真;如果没有异常的话,那么当前SessionScope的SQL操作都被提交。

endTransaction

类似startTransaction,都是转发给SqlMapExecutorDelegate的endTransaction。

  /**
   * End the transaction on a session
   *
   * @param sessionScope - the session
   * @throws SQLException - if the transaction could not be ended
   */
  public void endTransaction(SessionScope sessionScope) throws SQLException {
    try {
      try {
        sqlExecutor.cleanup(sessionScope);
      } finally {
        txManager.end(sessionScope);
      }
    } catch (TransactionException e) {
      throw new NestedSQLException("Error while ending transaction.  Cause: " + e, e);
    }
  }

TransactionManager的end

  public void end(SessionScope sessionScope) throws SQLException, TransactionException {
    Transaction trans = sessionScope.getTransaction();
    TransactionState state = sessionScope.getTransactionState();

    if (state == TransactionState.STATE_USER_PROVIDED) {
      throw new TransactionException("TransactionManager could not end this transaction.  " +
          "A user provided connection is currently being used by this session.  " +
          "You must call the rollback() method of the Connection directly.  " +
          "The calling .setUserConnection (null) will clear the user provided transaction.");
    }

    try {
      if (trans != null) {
        try {
          if (state != TransactionState.STATE_COMMITTED) {
            if (sessionScope.isCommitRequired() || config.isForceCommit()) {
              trans.rollback();
              sessionScope.setCommitRequired(false);
            }
          }
        } finally {
          sessionScope.closePreparedStatements();
          trans.close();
        }
      }
    } finally {
      sessionScope.setTransaction(null);
      sessionScope.setTransactionState(TransactionState.STATE_ENDED);
    }
  }

事务的提交操作会根据当前SessionScope的事务信息判断是否需要回滚,只有当前事务状态为非提交状态,同时,提交标识为真时,才会调用Transaction的rollback操作。在两种情况下会出现SQL的回滚:

第一种,在MappedStatement的executeUpdate操作中,会设置事务的提交标识为真,并且只有在正确执行完成SQL后才会设置事务状态为已提交状态。如果整个流程中出现异常,那么这条SQL就会回滚。

第二种,用户执行了startTransaction,但是没有调用commitTransaction方法,那么这期间的SQL都会回滚。

Finally分支中会关闭所有的JDBC语句已经Connection,并设置事务状态为结束状态。至此,一次完整的SQL执行结束。

时间: 2024-08-27 03:13:08

项目开发-iBatis事务源码之事务提交和回滚的相关文章

切分大任务成多个子任务(事务),汇总后统一提交或回滚

示例代码可以从github上获取 https://github.com/git-simm/simm-framework.git 一.业务场景: 系统中存在一个盘库的功能,用户一次盘库形成一两万条的盘库明细单,一次性提交给服务器进行处理.服务器性能比较优越,平均也得运行30秒左右.性能上需要进行优化. 二.处理方案: 做过代码分析后,发现单线程逻辑没有什么优化空间.开始考虑引入多线程处理模型,用10个子线程进行任务切分处理.切分子线程问题需要考虑事务的一致性.10个子线程对应10个事务,需要保证所

iOS项目开发实战——网页源码实现二进制和HTML的转换

我们能够获取某个网页的源码,可是这个源码的形式能够是二进制.也能够是HTML,我们怎样实现这两种不同类型之间的转换呢?在IOS中能够使用一个方法实现简单的转化. 在viewDidiLoad() 中实现代码例如以下: override func viewDidLoad() { super.viewDidLoad() var binaryStr = NSData(contentsOfURL: NSURL(string: "http://www.baidu.com")!) println(&

项目开发-iBatis事务结构

阅读iBatis源码时,对事务相关的代码,没太关注,导致今天项目技术演练时对同事的疑问,解释不清楚.自己都不清楚的东西,怎么可能向别人解释清楚呢?所以,就干脆继续看iBatis源码,完整跟踪事务的处理流程.重新分析代码,发现iBatis原来使用了代理模式,同时理解了iBatis的线程安全的保证机制及事务控制流程. 顶层类图 线程安全的保证 iBatis的SqlMapClient和SqlMapSession有相同的继承关系,而SqlMapClient的实现类则关联了一个SqlMapSession的

结合ThreadLocal来看spring事务源码,感受下清泉般的洗涤!

在我的博客spring事务源码解析中,提到了一个很关键的点:将connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection.但是没有细致的讲到如何绑定,以及为什么这么绑定:另外也没有讲到连接池的相关问题:如何从连接池获取,如何归还连接到连接池等等.那么下面就请听我慢慢道来. ThreadLocal 讲spring事务之前,我们先来看看ThreadLocal,它在spring事务中是占据着比较重要的地位:不管你对ThreadLocal熟悉与否,且都静下心来听我唐僧

Spring 事务源码分析——Hibernate篇

在Spring与Hibernate整合的时候,可以利用Spring的事务管理机制,为我们管理事务的开启.提交.回滚等操作.这样的方式极大的减少了我们的代码量,让我们只专注于业务代码的编写.在使用Hibernate的时候,每一个操作都要经历事务开启与提交这样的操作,他们在业务代码的周围,这样来看是不是就想到了AOP编程,把这部分代码抽取出来.没错,Spring正是这样做的,Spring的事务管理就是基于AOP的. 1 Spring的事务隔离与传播 Srping的事务定义了五个隔离等级(isolat

spring事务源码研读1

转载摘录自:Spring事务源码分析(一)Spring事务入门 有时为了保证一些操作要么都成功,要么都失败,这就需要事务来保证. 传统的jdbc事务如下: @Test public void testAdd(){ Connection con=null; try { con=DriverManager.getConnection(url , username , password ) con.setAutoCommit(false); //操作一 PreparedStatement ps = c

RocketMQ源码分析之RocketMQ事务消息实现原下篇(事务提交或回滚)

本文将重点分析RocketMQ Broker如何处理事务消息提交.回滚命令,根据前面的介绍,其入口EndTransactionProcessor#proce***equest: OperationResult result = new OperationResult();if (MessageSysFlag.TRANSACTION_COMMIT_TYPE == requestHeader.getCommitOrRollback()) { // @1result = this.brokerCont

spring事务源码分析结合mybatis源码(二)

让我们继续上篇,分析下如果有第二个调用进入的过程. 代码部分主要是下面这个: if (isExistingTransaction(transaction)) { return handleExistingTransaction(definition, transaction, debugEnabled); } protected boolean isExistingTransaction(Object transaction) { DataSourceTransactionObject txOb

VC++环境下多文档模板应用程序开发(带源码)

我们以前见到的关于VC++环境下利用APP Wizard 自动生成的MDI的应用程序只支持打开同一文档类型的多个文件,但是不能够同时打开不同种类型的文档.网上的这种公开资料比较少,我在知网上查阅了相关的资料.下面我根据这些资料做一下总结(辛辛苦苦一个一个字码出来的). 下面设计一个能够处理两种文档类型的应用程序:第一种文档类型:TXT文档,第二种文档类型:Bub的文档类型. 第一种的文档类型TXT,是利用APP Wizard自动生成的,只不过是在设置的时候将文档类型设置为TXT类型,并且使生成的