1. 程式人生 > >Mybatis中的事物提交commit()方法

Mybatis中的事物提交commit()方法

本文轉至:https://blog.csdn.net/sunroyfcb/article/details/80517945 

Mybatis通過對JDBC進行封裝,極大地簡化了程式設計師對資料庫的操作,例如對資料庫的增刪改查操作。其中當進行增刪改操作時,都會涉及到使用者資料的提交,那麼Mybatis中究竟是如何完成資料的提交的呢?這裡將對Mybatis中的commit()方法進行簡單的剖析,看看底層是如何實現事物提交的。


       其實Mybatis中可以設定自動提交功能。在利用工廠模式獲得SqlSession實現類物件時,採用openSession(true),即可實現自動提交,無需呼叫commit()方法。但是程式是為了現實中的應用場景而產生的,現實中往往採用手動提交的方式,避免誤操作,因此通常使用的是openSession()方法,底層獲得了一個SqlSession介面的實現類DefaultSqlSession,這是它的構造方法,這裡提一句,dirty=false表示該物件中的資料與資料庫同步,不是髒資料。
 

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
}

 通過進入DefaultSqlSession類可以看到,我們進行增刪改操作,最終底層都會呼叫這個類中的update()方法,以下是update()方法:

public int update(String statement, Object parameter) {
    try {
      dirty = true;
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
}

 可以看到dirty=true,這裡將修改產生的資料暫時視為髒資料,即未與資料庫同步。

    當程式執行到commit()方法,即手動提交資料時,其實呼叫的是DefaultSqlSession類中的commit(false)方法。

//commit()方法呼叫過程
public void commit() {
    commit(false);
  }
 
public void commit(boolean force) {
    try {
      executor.commit(isCommitOrRollbackRequired(force));
      dirty = false;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
}

      這個方法的核心是執行器executor呼叫了commit()方法,先來看看方法內部的引數isCommitOrRollbackRequired(force)方法,這裡為或表示式,左邊為true直接短路返回true。

private boolean isCommitOrRollbackRequired(boolean force) {
    return (!autoCommit && dirty) || force;
}
public void commit(boolean force) {
    try {
      executor.commit(isCommitOrRollbackRequired(force));
      dirty = false;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
}

        因此執行器執行的方法是commit(true),執行完之後將dirty重新改為false,因為資料已經與資料庫同步,不再是髒資料。通過除錯可以知道,這裡的executor是Executor介面實現類CachingExecutor的物件:

public void commit(boolean required) throws SQLException {
    delegate.commit(required);
    tcm.commit();
}

   這裡首先進行了清空快取和重新整理資料,然後進行的事物提交,即transaction.commit(),這裡的transaction是Transaction介面實現類JdbcTransaction的物件,進入到這個類中,

public void commit() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) {
      if (log.isDebugEnabled()) {
        log.debug("Committing JDBC Connection [" + connection + "]");
      }
      connection.commit();
    }
}

        可以看到底層呼叫的依然是java基礎api中的Connection中的commit方法,這也再一次證明了Mybatis框架實際上是對Jdbc的封裝。