mybatis系列-sql 类的简要分析

上次就比较简单的讲了使用,这块也比较简单,因为封装得不是很复杂,首先我们从 select 作为入口来看看,这个具体的实现,

String selectSql = new SQL() {{
            SELECT("id", "name");
            FROM("student");
            WHERE("id = #{id}");
        }}.toString();

SELECT 方法的实现,

public T SELECT(String... columns) {
  sql().statementType = SQLStatement.StatementType.SELECT;
  sql().select.addAll(Arrays.asList(columns));
  return getSelf();
}

statementType是个枚举

public enum StatementType {
  DELETE, INSERT, SELECT, UPDATE
}

那这个就是个 select 语句,然后会把参数转成 list 添加到 select 变量里,
然后是 from 语句,这个大概也能猜到就是设置下表名,

public T FROM(String table) {
  sql().tables.add(table);
  return getSelf();
}

往 tables 里添加了 table,这个 tables 是什么呢
这里也可以看下所有的变量,

StatementType statementType;
List<String> sets = new ArrayList<>();
List<String> select = new ArrayList<>();
List<String> tables = new ArrayList<>();
List<String> join = new ArrayList<>();
List<String> innerJoin = new ArrayList<>();
List<String> outerJoin = new ArrayList<>();
List<String> leftOuterJoin = new ArrayList<>();
List<String> rightOuterJoin = new ArrayList<>();
List<String> where = new ArrayList<>();
List<String> having = new ArrayList<>();
List<String> groupBy = new ArrayList<>();
List<String> orderBy = new ArrayList<>();
List<String> lastList = new ArrayList<>();
List<String> columns = new ArrayList<>();
List<List<String>> valuesList = new ArrayList<>();

可以看到是一堆 List 先暂存这些sql 片段,然后再拼装成 sql 语句,
因为它重写了 toString 方法

@Override
public String toString() {
  StringBuilder sb = new StringBuilder();
  sql().sql(sb);
  return sb.toString();
}

调用的 sql 方法是

public String sql(Appendable a) {
      SafeAppendable builder = new SafeAppendable(a);
      if (statementType == null) {
        return null;
      }

      String answer;

      switch (statementType) {
        case DELETE:
          answer = deleteSQL(builder);
          break;

        case INSERT:
          answer = insertSQL(builder);
          break;

        case SELECT:
          answer = selectSQL(builder);
          break;

        case UPDATE:
          answer = updateSQL(builder);
          break;

        default:
          answer = null;
      }

      return answer;
    }

根据上面的 statementType判断是个什么 sql,我们这个是 selectSQL 就走的 SELECT 这个分支

private String selectSQL(SafeAppendable builder) {
  if (distinct) {
    sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");
  } else {
    sqlClause(builder, "SELECT", select, "", "", ", ");
  }

  sqlClause(builder, "FROM", tables, "", "", ", ");
  joins(builder);
  sqlClause(builder, "WHERE", where, "(", ")", " AND ");
  sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
  sqlClause(builder, "HAVING", having, "(", ")", " AND ");
  sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
  limitingRowsStrategy.appendClause(builder, offset, limit);
  return builder.toString();
}

上面的可以看出来就是按我们常规的 sql 理解顺序来处理
就是select ... from ... where ...这样子
再看下 sqlClause 的代码

private void sqlClause(SafeAppendable builder, String keyword, List<String> parts, String open, String close,
                           String conjunction) {
      if (!parts.isEmpty()) {
        if (!builder.isEmpty()) {
          builder.append("\n");
        }
        builder.append(keyword);
        builder.append(" ");
        builder.append(open);
        String last = "________";
        for (int i = 0, n = parts.size(); i < n; i++) {
          String part = parts.get(i);
          if (i > 0 && !part.equals(AND) && !part.equals(OR) && !last.equals(AND) && !last.equals(OR)) {
            builder.append(conjunction);
          }
          builder.append(part);
          last = part;
        }
        builder.append(close);
      }
    }

这里的拼接方式还需要判断 AND 和 OR 的判断逻辑,其他就没什么特别的了,只是where 语句中的 lastList 不知道是干嘛的,好像只有添加跟赋值的操作,有知道的大神也可以评论指导下