MyabtisPlus(2):最终拼接SQL

1,304 阅读1分钟

既然知道Mybatis是对JDBC的封装,说明拼接SQL最终也是用的staticSql和bindValues,只要找到相应的代码即可认证。

staticSql

MybatisReuseExecutor->doQuery():
    stmt = prepareStatement(handler, ms.getStatementLog(), false);
MybatisReuseExecutor->prepareStatement():
    stmt = handler.prepare(connection, transaction.getTimeout());
RoutingStatementHandler->prepare():
    return delegate.prepare(connection, transactionTimeout);
BaseStatementHandler->prepare():
     statement = instantiateStatement(connection);
PreparedStatementHandler->instantiateStatement():
    return connection.prepareStatement(sql);
DruidPooledConnection->prepareStatement():
    // conn.prepareStatement(sql)最终调用conn.prepareStatement(),在这边设置了staticSql
    stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql));

bindValues

MybatisReuseExecutor->doQuery():
    stmt = prepareStatement(handler, ms.getStatementLog(), false);
MybatisReuseExecutor->prepareStatement():
    handler.parameterize(stmt);
RoutingStatementHandler->parameterize():
    delegate.parameterize(statement);
PreparedStatementHandler->parameterize():
    parameterHandler.setParameters((PreparedStatement) statement);
MybatisDefaultParameterHandler->setParameters():
    // parameterMappings是参数信息,有几个预编译符#就有几个parameterMapping
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    ......
    // propertyName是预编译符大括号里的值
    String propertyName = parameterMapping.getProperty();
    ......
    // 如果参数对象对应JDBC类型的话,value就是该参数值
    // 只有单个参数不带@Param注解且对应JDBC类型的时候,才会直接返回parameterObject
    // 例如(Integer id → #{id})
    else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
        value = parameterObject;
    } else {
        // 否则都是利用MetaObject的方式获得该值(如果是基本类型,最终调用map.get,否则调用的是getName反射方法)
        // 假如是(@Param("id") Integer id → #{id}),那么调用map.get("id");
        // 假如是(Tree tree → #{tree.id}),那么调用Tree.getTree(),报错;
        // 假如是(@Param("tree")Tree tree → #{tree.id}),那么调用map.get("tree")返回tree对象,再调用tree.getId()返回值
        // 假如是(@Param("ew") QueryWrapper queryWrapper → ${ew.sqlSegment},会先解析成#{ew.paramNameValuePairs.MPGENVAL1},先调用map.get("ew")得到QueryWrapper,然后调用QueryWrapper.getParamNameValuePairs()得到map,然后调用map.get("MPGENVAL1")得到设定值)
        MetaObject metaObject = configuration.newMetaObject(parameterObject);
        value = metaObject.getValue(propertyName);
    }
    ......
    // 得到value值后,根据其对应的JDBC类型选择相应的类型处理器
    typeHandler.setParameter(ps, i + 1, value, jdbcType);
BaseTypeHandler->setParameter():
    setNonNullParameter(ps, i, parameter, jdbcType);
UnknownTypeHandler->setNonNullParameter():
    // 根据参数类型获得处理器类型,如实是Integer类型的话就是IntegerTypeHandler
    TypeHandler handler = resolveTypeHandler(parameter, jdbcType);
    handler.setParameter(ps, i, parameter, jdbcType);
BaseTypeHandler->setParameter():
    setNonNullParameter(ps, i, parameter, jdbcType);
IntegerTypeHandler->setNonNullParameter():
    //  因为是Integer类型处理器,所以最终调用ps.setInt(),在这边设置了bindValues
    ps.setInt(i, parameter);           

总结与反思:

  1. 无论是查询,还是更新,都是通过prepareStatement(handler, ms.getStatementLog(), false)实现的