mybatis源码之mybatis-plus执行查询(基础篇完结)

在 mybatis源码分析_06_mybatis-plus源码分析 一文中,我们了解到了mybatis-plus的核心原理,知道了Wrapper构建动态SQL的过程,对于执行流程没有展开分析,虽然与mybatis很相似,但是仍然存在一些问题没有解决,比如:

  • 动态SQL中的ew是什么,他是怎么来的
  • 动态SQL中的entity是什么,他是怎么来的
  • 动态SQL中的sqlSegment是什么,他是怎么来的
  • 动态SQL中的其余几个参数:nonEmptyOfWhere、nonEmptyOfEntity、nonEmptyOfNormal、emptyOfWhere是怎么来的

本文将通过源码分析以上几个问题。


系列文章:

  • mybatis源码之创建SqlSessionFactory代码分析
  • mybatis源码之创建SqlSessionFactory代码分析 - mapper xml解析
  • mybatis源码之执行查询SQL代码分析
  • mybatis源码之执行insert代码分析
  • mybatis源码之mapper接口扫描原理分析
  • mybatis源码之集成spring原理
  • mybatis源码之集成springboot原理
  • mybatis源码之集成mybatis-plus源码
  • mybatis源码之mybatis-plus执行查询(基础篇完结)
  • MybatisPlusAutoConfiguration源码分析
  • Autowired注入Service变成了biaomidou的Mapper代理

ew的来源

在BaseMapper接口里面:

List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// String WRAPPER = "ew";

这个是selectList方法的声明,可以看到参数加了@Param注解,注解的value就是ew。

回顾getMapper(Class)方法

入口和MybatisMapperProxyFactory

之前我们分析过mybatis-plus的getMapper(Class)方法,最终走到MybatisMapperRegistry的getMapper(Class)方法中:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 这里换成MybatisMapperProxyFactory而不是MapperProxyFactory
    // 这行代码之前分析过了
    final MybatisMapperProxyFactory<T> mapperProxyFactory = knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry.");
    }
    try {
        // 这里很重要,是在创建代理对象
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

mapperProxyFactory.newInstance(sqlSession)创建代理对象,MybatisMapperProxyFactory类:

public class MybatisMapperProxyFactory<T> {
    
    @Getter
    private final Class<T> mapperInterface;
    @Getter
    private final Map<Method, MybatisMapperProxy.MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
    
    public MybatisMapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    @SuppressWarnings("unchecked")
    protected T newInstance(MybatisMapperProxy<T> mapperProxy) {
        return (T) Proxy.newProxyInstance(
            mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        final MybatisMapperProxy<T> mapperProxy = 
            new MybatisMapperProxy<>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
    }
}

这个类与mybatis的MapperProxyFactory类似,只是这个类使用的是mybatis-plus的MybatisMapperProxy作为代理InvocationHandler实现。

MybatisMapperProxy

这类实现了InvocationHandler接口,InvocationHandler接口的invoke方法在代理对象拦截到目标方法时执行,看一下MybatisMapperProxy的invoke方法的实现:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        } else {
            // 我们关注的是这个分支
            return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
        }
    } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
    }
}

// 首先从methodCache中获取目标method的MapperMethodInvoker的实现
// 如果没有就创建一个新的
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
    try {
        return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
            // 这个分支是判断default方法,不需要关注
            if (m.isDefault()) {
                try {
                    if (privateLookupInMethod == null) {
                        return new DefaultMethodInvoker(getMethodHandleJava8(method));
                    } else {
                        return new DefaultMethodInvoker(getMethodHandleJava9(method));
                    }
                } catch (IllegalAccessException | InstantiationException | InvocationTargetException
                    | NoSuchMethodException e) {
                    throw new RuntimeException(e);
                }
            } else {
                // 这个创建一个PlainMethodInvoker实现对象
                // 需要传递一个MybatisMapperMethod对象作为参数
                // 这两个类都由mybatis-plus提供
                return new PlainMethodInvoker(
                    new MybatisMapperMethod(
                        mapperInterface, method, sqlSession.getConfiguration()
                    )
                );
            }
        });
    } catch (RuntimeException re) {
        // ...
    }
}

PlainMethodInvoker类,看一下代码就行,不需要特别说明:

private static class PlainMethodInvoker implements MapperMethodInvoker {
    private final MybatisMapperMethod mapperMethod;
    
    public PlainMethodInvoker(MybatisMapperMethod mapperMethod) {
        super();
        this.mapperMethod = mapperMethod;
    }
    
    @Override
    public Object invoke(
        Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
        // 调用mapperMethod的execute方法
        return mapperMethod.execute(sqlSession, args);
    }
}

需要看一下MybatisMapperMethod类。

MybatisMapperMethod类

这个类与mybatis提供的MapperMethod类似,先看一下构造方法:

public class MybatisMapperMethod {
    private final MapperMethod.SqlCommand command;
    private final MapperMethod.MethodSignature method;

    public MybatisMapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
        // select、insert、update、delete等
        this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
        // 这里比较重要
        this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
    }
    // ...
}

// 以下内容都是mybatis提供的了:
// MapperMethod.MethodSignature
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
  Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
  if (resolvedReturnType instanceof Class<?>) {
    this.returnType = (Class<?>) resolvedReturnType;
  } else if (resolvedReturnType instanceof ParameterizedType) {
    this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
  } else {
    this.returnType = method.getReturnType();
  }
  this.returnsVoid = void.class.equals(this.returnType);
  this.returnsMany = 
      configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
  this.returnsCursor = Cursor.class.equals(this.returnType);
  this.returnsOptional = Optional.class.equals(this.returnType);
  this.mapKey = getMapKey(method);
  this.returnsMap = this.mapKey != null;
  this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
  this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
  // 这里创建ParamNameResolver,用于解析方法参数
  this.paramNameResolver = new ParamNameResolver(configuration, method);
}

// ParamNameResolver
public ParamNameResolver(Configuration config, Method method) {
  // 这个默认是true
  this.useActualParamName = config.isUseActualParamName();
  // 参数列表
  final Class<?>[] paramTypes = method.getParameterTypes();
  // 所有参数所有注解
  final Annotation[][] paramAnnotations = method.getParameterAnnotations();
  final SortedMap<Integer, String> map = new TreeMap<>();
  // 参数个数
  int paramCount = paramAnnotations.length;
  // get names from @Param annotations
  for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
    // 这个分支进不来
    if (isSpecialParameter(paramTypes[paramIndex])) {
      // skip special parameters
      continue;
    }
    String name = null;
    // 遍历参数的所有注解
    for (Annotation annotation : paramAnnotations[paramIndex]) {
      // 只解析@Param注解
      if (annotation instanceof Param) {
        hasParamAnnotation = true;
        // 获取到Param名,selectList方法的话这里的值是ew
        name = ((Param) annotation).value();
        break;
      }
    }
    if (name == null) {
      // @Param was not specified.
      if (useActualParamName) {
        // 这里解析成arg0、arg1 ...
        name = getActualParamName(method, paramIndex);
      }
      if (name == null) {
        // use the parameter index as the name ("0", "1", ...)
        // gcode issue #71
        name = String.valueOf(map.size());
      }
    }
    map.put(paramIndex, name);
  }
  // 得到一个Map结构
  // index -> param name
  // selectList方法的话,就是0->ew
  names = Collections.unmodifiableSortedMap(map);
}

看一下execute方法:

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
        case INSERT: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
        }
        case UPDATE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
        }
        case DELETE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
        }
        case SELECT:
            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 if (method.returnsCursor()) {
                result = executeForCursor(sqlSession, args);
            } else {
                // TODO 这里下面改了
                if (IPage.class.isAssignableFrom(method.getReturnType())) {
                    result = executeForIPage(sqlSession, args);
                    // TODO 这里上面改了
                } else {
                    Object param = method.convertArgsToSqlCommandParam(args);
                    result = sqlSession.selectOne(command.getName(), param);
                    if (method.returnsOptional()
                        && (result == null || !method.getReturnType().equals(result.getClass()))) {
                        result = Optional.ofNullable(result);
                    }
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            // 抛异常
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        // 抛异常
    }
    return result;
}

private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    // MapperMethod.MethodSignature method
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
        RowBounds rowBounds = method.extractRowBounds(args);
        result = sqlSession.selectList(command.getName(), param, rowBounds);
    } else {
        result = sqlSession.selectList(command.getName(), param);
    }
    // issue #510 Collections & arrays support
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
        if (method.getReturnType().isArray()) {
            return convertToArray(result);
        } else {
            return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
        }
    }
    return result;
}

executeForMany方法之前在 mybatis源码分析_03_mapper接口源码分析 一文中做过分析,不过当时没有详细分析convertArgsToSqlCommandParam的流程,此处需要补充一下这部分内容,因为这与mybatis-plus的核心查询流程关系密切。

method.convertArgsToSqlCommandParam(args)方法

public Object convertArgsToSqlCommandParam(Object[] args) {
  return paramNameResolver.getNamedParams(args);
}

// paramNameResolver.getNamedParams(args)
public Object getNamedParams(Object[] args) {
  final int paramCount = names.size();
  if (args == null || paramCount == 0) {
    return null;
  } else if (!hasParamAnnotation && paramCount == 1) {
    // hasParamAnnotation = true所以这个分支进不来
    Object value = args[names.firstKey()];
    return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);
  } else {
    // 用于封装参数,例如ew -> LambdaQueryWrapper参数对象
    // 或者param1 -> LambdaQueryWrapper参数对象
    final Map<String, Object> param = new ParamMap<>();
    int i = 0;
    for (Map.Entry<Integer, String> entry : names.entrySet()) {
      // entry: 0 -> ew
      param.put(entry.getValue(), args[entry.getKey()]);
      // add generic param names (param1, param2, ...)
      final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
      // ensure not to overwrite parameter named with @Param
      if (!names.containsValue(genericParamName)) {
        param.put(genericParamName, args[entry.getKey()]);
      }
      i++;
    }
    return param;
  }
}

所以到这里我们就可以知道ew就是selectList方法的参数,也就是LambdaQueryWrapper参数对象。

回顾动态SQL

回顾动态SQL

我们之前看过格式化后的动态SQL:

<script>
  <choose>
    <when test="ew != null and ew.sqlFirst != null">
      ${ew.sqlFirst}
    </when>
    <otherwise></otherwise>
  </choose> SELECT 
  <!-- 拼接查询字段 -->
  <choose>
    <when test="ew != null and ew.sqlSelect != null">
      ${ew.sqlSelect}
    </when>
    <otherwise>id,title,content,create_time,update_time</otherwise>
  </choose> FROM blog  <!-- 拼接表名 -->
  <!-- 拼接查询条件 -->
  <if test="ew != null">
    <where>
      <!-- 拼接实体对象查询条件 -->
      <if test="ew.entity != null">
        <if test="ew.entity.id != null">id=#{ew.entity.id}</if>
        <if test="ew.entity['title'] != null"> AND title=#{ew.entity.title}</if>
        <if test="ew.entity['content'] != null"> AND content=#{ew.entity.content}</if>
        <if test="ew.entity['createTime'] != null"> AND create_time=#{ew.entity.createTime}</if>
        <if test="ew.entity['updateTime'] != null"> AND update_time=#{ew.entity.updateTime}</if>
      </if>
      <!-- 拼接Wrapper对象查询条件 -->
      <if test="ew.sqlSegment != null and ew.sqlSegment != '' and ew.nonEmptyOfWhere">
        <if test="ew.nonEmptyOfEntity and ew.nonEmptyOfNormal"> AND</if> ${ew.sqlSegment}
      </if>
    </where>
    <!-- 拼接Wrapper对象查询条件,这里通常没有办法进来,存在疑问 -->
    <if test="ew.sqlSegment != null and ew.sqlSegment != '' and ew.emptyOfWhere">
      ${ew.sqlSegment}
    </if>
  </if> 
  <choose>
    <when test="ew != null and ew.sqlComment != null">
      ${ew.sqlComment}
    </when>
    <otherwise></otherwise>
  </choose>
script>

ew属性

在前面的分析中,可以知道ew就是方法的参数,也就是LambdaQueryWrapper参数对象。

ew.entity属性

这个属性定义在AbstractWrapper类中,用于获取实体类查询条件:

private T entity;

public T getEntity() {
  return entity;
}

用于为以下动态SQL赋值:

<if test="ew.entity != null">
  <if test="ew.entity.id != null">id=#{ew.entity.id}if>
  <if test="ew.entity['title'] != null"> AND title=#{ew.entity.title}if>
  <if test="ew.entity['content'] != null"> AND content=#{ew.entity.content}if>
  <if test="ew.entity['createTime'] != null"> AND create_time=#{ew.entity.createTime}if>
  <if test="ew.entity['updateTime'] != null"> AND update_time=#{ew.entity.updateTime}if>
if>

ew.sqlSegment属性

这个属性定义在ISqlSegment接口中,用于获取动态查询SQL代码片段:

@FunctionalInterface
public interface ISqlSegment extends Serializable {

  String getSqlSegment();
}

他有几个重要的实现类:

  • AbstractWrapper
  • MergeSegments
  • SqlKeyword

在之前分析LambdaQueryWrapper的时候介绍过MergeSegments类,在AbstractWrapper中使用他封装所有的动态条件表达式,也看过add动态条件表达式的代码。

AbstractWrapper.getSqlSegment()方法:

public String getSqlSegment() {
  return expression.getSqlSegment() + lastSql.getStringValue();
}

// 这个是expression是MergeSegments对象,用于聚合了其他类型的ISqlSegment对象

MergeSegments.getSqlSegment()方法:

public String getSqlSegment() {
    if (cacheSqlSegment) {
        return sqlSegment;
    }
    cacheSqlSegment = true;
    if (normal.isEmpty()) {
        if (!groupBy.isEmpty() || !orderBy.isEmpty()) {
            sqlSegment = groupBy.getSqlSegment() + having.getSqlSegment() + orderBy.getSqlSegment();
        }
    } else {
        sqlSegment = normal.getSqlSegment() + groupBy.getSqlSegment() + having.getSqlSegment() + orderBy.getSqlSegment();
    }
    return sqlSegment;
}

// normal.getSqlSegment()
public String getSqlSegment() {
    if (cacheSqlSegment) {
        return sqlSegment;
    }
    cacheSqlSegment = true;
    sqlSegment = childrenSqlSegment();
    return sqlSegment;
}

// NormalSegmentList.childrenSqlSegment()
protected String childrenSqlSegment() {
    if (MatchSegment.AND_OR.match(lastValue)) {
        removeAndFlushLast();
    }
    // 这里拼接动态查询SQL代码片段
    final String str = this.stream().map(ISqlSegment::getSqlSegment).collect(Collectors.joining(SPACE));
    return (LEFT_BRACKET + str + RIGHT_BRACKET);
}

SqlKeyword.getSqlSegment()方法:

public enum SqlKeyword implements ISqlSegment {
    AND("AND"), OR("OR"), NOT("NOT"), IN("IN"), NOT_IN("NOT IN"),
    LIKE("LIKE"), NOT_LIKE("NOT LIKE"), EQ(StringPool.EQUALS),
    NE("<>"), GT(StringPool.RIGHT_CHEV), GE(">="), LT(StringPool.LEFT_CHEV),
    LE("<="), IS_NULL("IS NULL"), IS_NOT_NULL("IS NOT NULL"), GROUP_BY("GROUP BY"),
    HAVING("HAVING"), ORDER_BY("ORDER BY"), EXISTS("EXISTS"), NOT_EXISTS("NOT EXISTS"),
    BETWEEN("BETWEEN"), NOT_BETWEEN("NOT BETWEEN"), ASC("ASC"), DESC("DESC");

    private final String keyword;

    @Override
    public String getSqlSegment() {
        return this.keyword;
    }
}

其余属性

ew.nonEmptyOfWhere

这个属性定义在Wrapper类中,用于判断查询条件不为空:

public boolean nonEmptyOfWhere() {
    return !isEmptyOfWhere();
}

public boolean isEmptyOfWhere() {
    return isEmptyOfNormal() && isEmptyOfEntity();
}

ew.nonEmptyOfEntity

这个属性定义在Wrapper类中,用于深层实体判断属性:

public boolean isEmptyOfEntity() {
    return !nonEmptyOfEntity();
}

public boolean nonEmptyOfEntity() {
    T entity = getEntity();
    if (entity == null) {
        return false;
    }
    TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
    if (tableInfo == null) {
        return false;
    }
    if (tableInfo.getFieldList().stream().anyMatch(e -> fieldStrategyMatch(entity, e))) {
        return true;
    }
    return StringUtils.isNotBlank(tableInfo.getKeyProperty()) ? 
        Objects.nonNull(ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty())) : false;
}

ew.nonEmptyOfNormal

这个属性定义在Wrapper类中,用于判断查询条件不为空:

public boolean nonEmptyOfNormal() {
    return !isEmptyOfNormal();
}

public boolean isEmptyOfNormal() {
    return CollectionUtils.isEmpty(getExpression().getNormal());
}

ew.emptyOfWhere

这个属性定义在Wrapper类中,用于判断where条件不为空:

public boolean isEmptyOfWhere() {
    return isEmptyOfNormal() && isEmptyOfEntity();
}

你可能感兴趣的:(mybatis,java技术,mybatis,java,mysql)