成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

mybatis參數(shù)解析

shevy / 1220人閱讀

摘要:一簡介是支持定制化存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的持久層框架。避免了幾乎所有的代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集??梢詫?duì)配置和原生使用簡單的或注解,將接口和的普通的對(duì)象映射成數(shù)據(jù)庫中的記錄。三其他類型的參數(shù)我懶,不想寫了我的心愿是世界和平

(一)MyBatis簡介

MyBatis 是支持定制化 SQL、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的持久層框架。MyBatis 避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集。MyBatis 可以對(duì)配置和原生Map使用簡單的 XML 或注解,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對(duì)象)映射成數(shù)據(jù)庫中的記錄。

(二)源碼分析

項(xiàng)目是用映射器(dao)和映射文件(xxx.xml)的方式配置mybatis

先以下面的更新方法為例

dao接口的方法如下:
int updateSubjectById(Subject subject)throws Exception;

代碼執(zhí)行dao方法時(shí),會(huì)調(diào)用MapperProxy類中的invoke()方法,往下執(zhí)行會(huì)依次會(huì)調(diào)用
MapperMethod中的public Object execute(SqlSession sqlSession, Object[] args),

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    if (SqlCommandType.INSERT == command.getType()) {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE == command.getType()) {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE == command.getType()) {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT == command.getType()) {
        if (method.returnsVoid() && method.hasResultHandler()) {
            executeWithResultHandler(sqlSession, args);
            result = null;
        } else if (method.returnsMany()) {
            result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
            result = executeForMap(sqlSession, args);
        } else {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = sqlSession.selectOne(command.getName(), param);
        }
    } else if (SqlCommandType.FLUSH == command.getType()) {
        result = sqlSession.flushStatements();
    } else {
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        throw new BindingException("Mapper method "" + command.getName() 
            + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
}

MethodSignature中的public Object convertArgsToSqlCommandParam(Object[] args),

public Object convertArgsToSqlCommandParam(Object[] args) {
    final int paramCount = params.size();
    if (args == null || paramCount == 0) {
        return null;
    } else if (!hasNamedParameters && paramCount == 1) {
        return args[params.keySet().iterator().next().intValue()];
    } else {
        final Map param = new ParamMap();
        int i = 0;
        for (Map.Entry entry : params.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey().intValue()]);
            // issue #71, add param names as param1, param2...but ensure backward compatibility
            final String genericParamName = "param" + String.valueOf(i + 1);
            if (!param.containsKey(genericParamName)) {
                param.put(genericParamName, args[entry.getKey()]);
            }
            i++;
        }
        return param;
    }
}

因?yàn)閐ao中方法的參數(shù)為Subject subject,所以這里args參數(shù)為

hasNamedParameters意思是是否使用了注解參數(shù),這里沒有用到注解,值為false。
這里params.size()的值為1,如圖

所以上面的方法返回的是subject,excute()中的param就是subject。
convertArgsToSqlCommandParam()方法執(zhí)行完后,依次進(jìn)入rowCountResult(sqlSession.update(command.getName(), param)),SqlSessionTemplate中update()方法,

public int update(String statement, Object parameter) {
    return this.sqlSessionProxy.update(statement, parameter);
}

這時(shí)SqlSessionInterceptor攔截器(SqlSessiontemplate中的私有類)會(huì)攔截到。

private class SqlSessionInterceptor implements InvocationHandler {
    ...
    Object result=method.invoke(sqlSession, args);
    ...
}

其中arg[0]的值為com.services.forum.dao.SubjectDAO.updateSubjectById()方法,args[1]的值為SqlSessionTemplate中public int update(String statement, Object parameter)中的parameter,即dao層方法中傳的subject對(duì)象。
this.sqlSessionProxy的類型為DefaultSqlSession,其中update(...)方法return executor.update(ms, wrapCollection(parameter)); ,wrapCollection(parameter)對(duì)參數(shù)進(jìn)行包裝,該方法的實(shí)現(xiàn)如下:

private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
        StrictMap map = new StrictMap();
        map.put("collection", object);
        if (object instanceof List) {
            map.put("list", object);
        }
        return map;
    } else if (object != null && object.getClass().isArray()) {
        StrictMap map = new StrictMap();
        map.put("array", object);
        return map;
    }
    return object;
}

此方法首先定義一個(gè)StrictMap,

如果參數(shù)類型是Collection的子類,則在map中加入一條entry:("collection", object),返回map

如果參數(shù)類型是List的子類,則在map中加入一條entry:("list", object),返回map

如果參數(shù)是數(shù)組,則在map中加入一條entry:("array", object),返回map

否則返回參數(shù)object

隨后會(huì)執(zhí)行以下方法:
SimpleExecutor
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException
    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
Configuration
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
RoutingStatementHandler
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandl    er resultHandler, BoundSql boundSql){
    ...
    delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    ...
} 
PreparedStatementHandler
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBound    s, ResultHandler resultHandler, BoundSql boundSql) {
      super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
BaseStatementHandler
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds row    Bounds, ResultHandler resultHandler, BoundSql boundSql) {
    ...
    boundSql = mappedStatement.getBoundSql(parameterObject);
    ...
}
MappedStatement
public BoundSql getBoundSql(Object parameterObject) {
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    ...
}

再跟幾步會(huì)進(jìn)入DynamicSqlSource類中的getBoundSql()方法

public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    rootSqlNode.apply(context);
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    for (Map.Entry entry : context.getBindings().entrySet()) {
        boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
  return boundSql;
}

這個(gè)方法是生成sql語句的方法
sqlSourceParser中是設(shè)置和一些注冊(cè)的類型[處理機(jī)的]別名,如下圖

再跟到SqlSourceBuilder中的parse()方法,

public SqlSource parse(String originalSql, Class parameterType, Map additionalParameters) {
    ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalPara        meters);
    GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
    String sql = parser.parse(originalSql);
    return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}

該方法中有個(gè) originalSql參數(shù),這是sql映射文件中的原始sql語句,

update t_forum_subject SET title=#{title}, brief=#{brief}, is_top=#{isTop}, is_open=#{isOpen}, last_modify_time=#{lastModifyTime}, last_modify_userid=#{lastModifyUserId} where id=#{id} and enable=1 

GenericTockenParser類中的public String parse(String text)方法將originalSql中的#{}轉(zhuǎn)為了?,并且在handler的屬性parameterMappings中添加相應(yīng)的映射

public String parse(String text) {
    ...
    builder.append(handler.handleToken(content));
    ...
}
SqlSourceBuilder
@Override
public String handleToken(String content) {
    parameterMappings.add(buildParameterMapping(content));
    return "?";
}


再回到DynamicSqlSource類中g(shù)etBoundSql方法中,
現(xiàn)在sqlSource中sql屬性值變?yōu)?/p>

update t_forum_subject SET title=?, brief=?, is_top=?, is_open=?, last_modify_time=?, last_modify_userid=? 
where id=? and enable=1


parmeterMappings屬性的值如上圖所示

boundSql的值如上圖

SimpleExecutor
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    return stmt;
}

最后進(jìn)入DefaultParameterhandler類中的

public void setParameters(PreparedStatement ps) {
  ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  List parameterMappings = boundSql.getParameterMappings();
  if (parameterMappings != null) {
    for (int i = 0; i < parameterMappings.size(); i++) {
      ParameterMapping parameterMapping = parameterMappings.get(i);
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
          value = boundSql.getAdditionalParameter(propertyName);
        } else if (parameterObject == null) {
          value = null;
        } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } else {
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        TypeHandler typeHandler = parameterMapping.getTypeHandler();
        JdbcType jdbcType = parameterMapping.getJdbcType();
        if (value == null && jdbcType == null) {
          jdbcType = configuration.getJdbcTypeForNull();
        }
        try {
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        } catch (TypeException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        } catch (SQLException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        }
      }
    }
  }
}

在這個(gè)方法中遍歷parameterMappings,將parameterMapping中property的值賦給propertyName,再通過

MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);

將subject對(duì)象中的值賦給value,然后typeHandler.setParameter(ps, i + 1, value, jdbcType);將value值加入到ps的ColumnMap, ColumnNames, ColumnValues,再執(zhí)行SimpleExecutor的doUpdate()中的return handler.update(stmt);

然后,就沒有然后了

這次更新操作就完成了。
(三)其他類型的參數(shù)

我懶,不想寫了

---------------------------------------EOF--------------------------------------

我的心愿是世界和平!~( ゜▽゜)つロ

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69820.html

相關(guān)文章

  • Mybatis源碼分析

    摘要:我認(rèn)為學(xué)習(xí)框架源碼分為兩步抓住主線,掌握框架的原理和流程理解了處理思路之后,再去理解面向?qū)ο笏枷牒驮O(shè)計(jì)模式的用法目前第一步尚有問題,需要多走幾遍源碼,加深下理解,一起加油 這篇文章我們來深入閱讀下Mybatis的源碼,希望以后可以對(duì)底層框架不那么畏懼,學(xué)習(xí)框架設(shè)計(jì)中好的思想; 架構(gòu)原理 架構(gòu)圖 showImg(https://segmentfault.com/img/remote/...

    lindroid 評(píng)論0 收藏0
  • mybatis深入理解(一)之 # 與 $ 區(qū)別以及 sql 預(yù)編譯

    摘要:在動(dòng)態(tài)解析階段,和會(huì)有不同的表現(xiàn)解析為一個(gè)預(yù)編譯語句的參數(shù)標(biāo)記符。其次,在預(yù)編譯之前已經(jīng)被變量替換了,這會(huì)存在注入問題。預(yù)編譯語句對(duì)象可以重復(fù)利用。默認(rèn)情況下,將對(duì)所有的進(jìn)行預(yù)編譯。總結(jié)本文主要深入探究了對(duì)和的不同處理方式,并了解了預(yù)編譯。 mybatis 中使用 sqlMap 進(jìn)行 sql 查詢時(shí),經(jīng)常需要?jiǎng)討B(tài)傳遞參數(shù),例如我們需要根據(jù)用戶的姓名來篩選用戶時(shí),sql 如下: sele...

    shadowbook 評(píng)論0 收藏0
  • MyBatis 源碼分析系列文章合集

    摘要:簡介我從七月份開始閱讀源碼,并在隨后的天內(nèi)陸續(xù)更新了篇文章??紤]到超長文章對(duì)讀者不太友好,以及拆分文章工作量也不小等問題。經(jīng)過兩周緊張的排版,一本小小的源碼分析書誕生了。我在寫系列文章中,買了一本書作為參考,這本書是技術(shù)內(nèi)幕。 1.簡介 我從七月份開始閱讀MyBatis源碼,并在隨后的40天內(nèi)陸續(xù)更新了7篇文章。起初,我只是打算通過博客的形式進(jìn)行分享。但在寫作的過程中,發(fā)現(xiàn)要分析的代碼...

    Crazy_Coder 評(píng)論0 收藏0
  • mybatis-spring原理解析

    摘要:創(chuàng)建出的是對(duì)象,持有這個(gè)對(duì)象。根據(jù)接口名和方法名從對(duì)象的中檢查并獲取方法對(duì)應(yīng)的語句解析成的對(duì)象,保存它的和命令類型。實(shí)現(xiàn)類攔截映射接口的自定義方法,讓去處理方法對(duì)應(yīng)的解析成的。 前言 Mybatis是目前主流的Java ORM框架之一。mybatis-spring包則是為了讓Mybatis更好得整合進(jìn)Spring的衍生產(chǎn)品。本文就從Mybatis和mybatis-spring源碼著手,...

    why_rookie 評(píng)論0 收藏0
  • 【深入淺出MyBatis筆記】MyBatis解析和運(yùn)行原理

    摘要:的解析和運(yùn)行原理構(gòu)建過程提供創(chuàng)建的核心接口。在構(gòu)造器初始化時(shí)會(huì)根據(jù)和的方法解析為命令。數(shù)據(jù)庫會(huì)話器定義了一個(gè)對(duì)象的適配器,它是一個(gè)接口對(duì)象,構(gòu)造器根據(jù)配置來適配對(duì)應(yīng)的對(duì)象。它的作用是給實(shí)現(xiàn)類對(duì)象的使用提供一個(gè)統(tǒng)一簡易的使用適配器。 MyBatis的解析和運(yùn)行原理 構(gòu)建SqlSessionFactory過程 SqlSessionFactory提供創(chuàng)建MyBatis的核心接口SqlSess...

    bitkylin 評(píng)論0 收藏0
  • Mybatis系列】從源碼角度理解Mybatis的$和#的作用

    摘要:原因就是傳入的和原有的單引號(hào),正好組成了,而后面恒等于,所以等于對(duì)這個(gè)庫執(zhí)行了查所有的操作。類比的執(zhí)行流程和原有的我們使用的方法就是。可以理解為就是用來解析定制的符號(hào)的語句。后續(xù)的流程,就和正常的流程一致了。 前言 在JDBC中,主要使用的是兩種語句,一種是支持參數(shù)化和預(yù)編譯的PrepareStatement,能夠支持原生的Sql,也支持設(shè)置占位符的方式,參數(shù)化輸入的參數(shù),防止Sql注...

    yanwei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

shevy

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<