项目开发-iBatis事务源码之SQL执行

接上篇,在开启事务后,执行SQL语句,整理SQL执行流程如下,以插入为例。

SqlMapClientImpl的insert

  public Object insert(String id, Object param) throws SQLException {
    return getLocalSqlMapSession().insert(id, param);
  }

SqlMapSessionImpl的insert

  public Object insert(String id, Object param) throws SQLException {
    return delegate.insert(sessionScope, id, param);
  }

SqlMapExecutorDelegate的insert

 /**
   * Call an insert statement by ID
   *
   * @param sessionScope - the session
   * @param id      - the statement ID
   * @param param   - the parameter object
   * @return - the generated key (or null)
   * @throws SQLException - if the insert fails
   */
  public Object insert(SessionScope sessionScope, String id, Object param) throws SQLException {
    Object generatedKey = null;

    MappedStatement ms = getMappedStatement(id);
    Transaction trans = getTransaction(sessionScope);
    boolean autoStart = trans == null;

    try {
      trans = autoStartTransaction(sessionScope, autoStart, trans);

      SelectKeyStatement selectKeyStatement = null;
      if (ms instanceof InsertStatement) {
        selectKeyStatement = ((InsertStatement) ms).getSelectKeyStatement();
      }

      // Here we get the old value for the key property. We'll want it later if for some reason the
      // insert fails.
      Object oldKeyValue = null;
      String keyProperty = null;
      boolean resetKeyValueOnFailure = false;
      if (selectKeyStatement != null && !selectKeyStatement.isRunAfterSQL()) {
        keyProperty = selectKeyStatement.getKeyProperty();
        oldKeyValue = PROBE.getObject(param, keyProperty);
        generatedKey = executeSelectKey(sessionScope, trans, ms, param);
        resetKeyValueOnFailure = true;
      }

      StatementScope statementScope = beginStatementScope(sessionScope, ms);
      try {
        ms.executeUpdate(statementScope, trans, param);
      }catch (SQLException e){
        // uh-oh, the insert failed, so if we set the reset flag earlier, we'll put the old value
        // back...
        if(resetKeyValueOnFailure) PROBE.setObject(param, keyProperty, oldKeyValue);
        // ...and still throw the exception.
        throw e;
      } finally {
        endStatementScope(statementScope);
      }

      if (selectKeyStatement != null && selectKeyStatement.isRunAfterSQL()) {
        generatedKey = executeSelectKey(sessionScope, trans, ms, param);
      }

      autoCommitTransaction(sessionScope, autoStart);
    } finally {
      autoEndTransaction(sessionScope, autoStart);
    }

    return generatedKey;
  }

添加操作会获取当前SessionScope的事务信息,如果没有事务,则添加一个默认事务,完成插入操作的自动提交

MappedStatement的executeUpdate方法

  public int executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject)
      throws SQLException {
    ErrorContext errorContext = statementScope.getErrorContext();
    errorContext.setActivity("preparing the mapped statement for execution");
    errorContext.setObjectId(this.getId());
    errorContext.setResource(this.getResource());

    statementScope.getSession().setCommitRequired(true);

    try {
      parameterObject = validateParameter(parameterObject);

      Sql sql = getSql();

      errorContext.setMoreInfo("Check the parameter map.");
      ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);

      errorContext.setMoreInfo("Check the result map.");
      ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);

      statementScope.setResultMap(resultMap);
      statementScope.setParameterMap(parameterMap);

      int rows = 0;

      errorContext.setMoreInfo("Check the parameter map.");
      Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);

      errorContext.setMoreInfo("Check the SQL statement.");
      String sqlString = sql.getSql(statementScope, parameterObject);

      errorContext.setActivity("executing mapped statement");
      errorContext.setMoreInfo("Check the statement or the result map.");
      rows = sqlExecuteUpdate(statementScope, trans.getConnection(), sqlString, parameters);

      errorContext.setMoreInfo("Check the output parameters.");
      if (parameterObject != null) {
        postProcessParameterObject(statementScope, parameterObject, parameters);
      }

      errorContext.reset();
      sql.cleanup(statementScope);
      notifyListeners();
      return rows;
    } catch (SQLException e) {
      errorContext.setCause(e);
      throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
    } catch (Exception e) {
      errorContext.setCause(e);
      throw new NestedSQLException(errorContext.toString(), e);
    }
  }

iBatis的增、删、改三种操作的SQL的最终都是调用MappedStatement的executeUpdate是执行,这三种操作都需要提交事务。所以操作执行时会设置SessionScope的事务提交标识为真。流程与insert类似,只是少了selectKey标签的处理。

时间: 2024-10-01 13:42:13

项目开发-iBatis事务源码之SQL执行的相关文章

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

接上篇继续事务的提交和结束流程如下. commitTransaction SqlMapClientImpl的commitTransaction操作,类似startTransaction,是最终由SqlMapExecutorDelege的commitTransaction完成的. /** * Commit the transaction on a session * * @param sessionScope - the session * @throws SQLException - if th

项目开发-iBatis事务结构

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

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

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

快速构建一个Spring Boot+MyBatis的项目IDEA(附源码下载)

如何快速构建一个Spring Boot的项目 工具 idea JDK版本 1.8 Spring Boot 版本 1.5.9 环境搭建实现:最基础前端可以访问到数据库内的内容 开始 IDEA 内部新建一个项目,项目类型选择Spring Initializr,Project SDK选择适合你当前环境的版本,这里我选择的是1.8(Spring Boot 2.0以上的版本,JDK选择请选择1.8即以上版本),构建服务选择默认就好,点击Next 填写Group和Artifact(此处我使用的是默认,请根据

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

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

基于S2SH开发车辆租赁管理系统 源码 BL

开发环境: Windows操作系统开发工具:MyEclipse/Eclipse + JDK+ Tomcat + MySQL 数据库 项目截图: 获取源码请联系博主-Q:782827013 原文地址:https://www.cnblogs.com/xlrjgzs/p/11145870.html

iOS开发-博客导出工具开发教程(附带源码)

前言: 作为一名学生, 作为一名iOS开发学习者, 我个人浏览信息包括博客, 更多的选择移动终端.然而, csdn并没有现成的客户端(不过有个web版的). 之前曾经看到一款开源的导出工具, 但是它是基于Windows平台的.导出的也仅仅是PDF格式.而且, 对于文章的导出, 需要精确URL.无法做到边浏览别导出. 另外, 我想实现的是, 可以在没有网络的情况下, 浏览自己收藏的文章.并且, 对于自己收藏的文章, 可以分类管理. 最关键的是, 对于自己的文章, 可以做一个备份.我曾经遇到过这样一

Java新手练习项目、毕业设计项目源码下载

最近自己做了个技术博客网站,整理了一下学习java过程中做的例子和小项目,都放在了网站了提供下载,有新手入门的例子,也有java web例子,还有本人大学期间的毕业设计源码,都可以下载.地址:微儿博客-Java新手练习项目.毕业设计项目源码下载

Android源码开发利器——Java源码调试(基于4.1.2)

原文地址:http://blog.csdn.net/jinzhuojun/article/details/8868038 调试Android Java源码 草帽的后花园--Neo 写在之前的话:这里主要是以调试Java源码为主,应该说是在system_process之后的源码,这对于调试和修改frameworks层的人来说真是一个利器,但至于为什么在system_process之后,我还在分析,如果有结果我会更新此文章,并正在尝试调试C++的代码,就是native中的代码,如果这个可行那将会大大