乐于分享
好东西不私藏

MyBatis 源码解读(八):动态 SQL 源码——<if>、<foreach> 背后的 OGNL 魔法

MyBatis 源码解读(八):动态 SQL 源码—— 背后的 OGNL 魔法

写在前面

如果你写过复杂查询,肯定用过 MyBatis 的动态 SQL:<if> 判断参数是否为空、<foreach> 遍历集合构建 IN 子句、<where> 自动处理 WHERE 关键字和多余的 AND……这些标签让 SQL 拼接从体力劳动变成了脑力劳动。

但问题来了:XML 里的 <if test="name != null"> 是怎么被解析的?test 里的表达式什么时候求值?<foreach> 的 opencloseseparator 是怎么拼到 SQL 里的?#{item} 为什么能取到集合里的元素?

这篇文章从 SqlNode 树、DynamicContext、OGNL 表达式三个维度,拆解动态 SQL 的完整生成过程。读完之后你应该能回答:为什么动态 SQL 只能在运行时解析?BoundSql 是怎么从一堆 XML 标签变成带 ? 占位符的 SQL 的?

一、动态 SQL vs 静态 SQL:什么时候需要动态解析

MyBatis 解析 XML 里的 <select><insert> 等标签时,会判断 SQL 是否包含动态内容:

  • 静态 SQL:纯文本,没有动态标签,没有 ${} 占位符 → 解析成 RawSqlSource
  • 动态 SQL:包含 <if><foreach><where> 等标签,或者有 ${} → 解析成 DynamicSqlSource
// XMLLanguageDriver.createSqlSource()
public SqlSource createSqlSource(
        Configuration configuration,
        XNode script, Class<?> parameterType)
{
    XMLScriptBuilder builder = new XMLScriptBuilder(
        configuration, script, parameterType);
return builder.parseScriptNode();
}

// XMLScriptBuilder.parseScriptNode()
public SqlSource parseScriptNode(){
// 递归解析 XML 子节点,生成 SqlNode 树
    SqlNode mixedSqlNode =
        parseDynamicTags(contextNode);
    SqlSource sqlSource;
if (isDynamic) {
        sqlSource = new DynamicSqlSource(
            configuration, mixedSqlNode);
    } else {
        sqlSource = new RawSqlSource(
            configuration, mixedSqlNode, parameterType);
    }
return sqlSource;
}

isDynamic 是在递归解析子节点时标记的:一旦发现 <if><choose><foreach><trim><where><set><bind> 等标签,或者有 ${} 占位符,就标记为动态。

这就像厨师看菜单:如果菜单上全是固定菜品,直接照做;如果有"根据顾客口味调整辣度"这种弹性描述,就得等顾客来了才能确定。

二、SqlNode:动态 SQL 的 AST(抽象语法树)

MyBatis 把每个动态标签都解析成一个 SqlNode,最终形成一棵树。SqlNode 的接口极简:

publicinterfaceSqlNode{
// 根据参数上下文解析自己,把 SQL 片段追加到 context
booleanapply(DynamicContext context);
}

apply 返回 true/false,表示当前节点是否"有内容"(比如 <if> 条件为 false 时,不追加任何内容,返回 false)。

SqlNode 的实现类对应各种动态标签:

SqlNode
  ├── MixedSqlNode —— 混合节点,包含多个子节点
  ├── StaticTextSqlNode —— 静态文本(不含动态标签的 SQL 片段)
  ├── IfSqlNode —— <if> 标签
  ├── ChooseSqlNode —— <choose> 标签(包含 <when>、<otherwise>)
  ├── ForEachSqlNode —— <foreach> 标签
  ├── TrimSqlNode —— <trim> 标签(<where>、<set> 的底层实现)
  ├── WhereSqlNode —— <where> 标签(继承 TrimSqlNode)
  ├── SetSqlNode —— <set> 标签(继承 TrimSqlNode)
  └── BindSqlNode —— <bind> 标签

2.1 MixedSqlNode:容器节点

publicclassMixedSqlNodeimplementsSqlNode{
privatefinal List<SqlNode> contents;

publicMixedSqlNode(List<SqlNode> contents){
this.contents = contents;
    }

@Override
publicbooleanapply(DynamicContext context){
for (SqlNode sqlNode : contents) {
            sqlNode.apply(context);
        }
returntrue;
    }
}

MixedSqlNode 是容器,里面装了一堆子节点。解析 XML 时,<select> 标签的所有子内容会被包装成一个 MixedSqlNode。递归调用每个子节点的 apply,把 SQL 片段逐个追加到 DynamicContext

这就像拼乐高:你手里有一堆小零件(SqlNode),按说明书(XML 结构)逐个拼到主体上(DynamicContext)。

2.2 IfSqlNode:条件分支

publicclassIfSqlNodeimplementsSqlNode{
privatefinal ExpressionEvaluator evaluator;
privatefinal String test;
privatefinal SqlNode contents;

publicIfSqlNode(SqlNode contents, String test){
this.test = test;
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
    }

@Override
publicbooleanapply(DynamicContext context){
if (evaluator.evaluateBoolean(test,
                context.getBindings())) {
            contents.apply(context);
returntrue;
        }
returnfalse;
    }
}

IfSqlNode 的核心:ExpressionEvaluator.evaluateBoolean() 用 OGNL 表达式求值。如果表达式结果为 true,执行子节点的 apply;否则什么都不做。

publicclassExpressionEvaluator{
publicbooleanevaluateBoolean(String expression,
            Object parameterObject)
{
        Object value = OgnlCache.getValue(
            expression, parameterObject);
if (value instanceof Boolean) {
return (Boolean) value;
        }
if (value instanceof Number) {
returnnew BigDecimal(
                String.valueOf(value))
                .compareTo(BigDecimal.ZERO) != 0;
        }
return value != null;
    }
}

OGNL 表达式从 parameterObject 里取值。比如 test="name != null",OGNL 会先从 context.getBindings() 里找 name 变量,然后判断是否为 null。

OGNL 是什么?Object-Graph Navigation Language,对象图导航语言。简单来说,就是可以通过类似 user.name 的表达式从对象里取值。Struts2 也用过 OGNL,不过 MyBatis 用的是精简版,只保留了表达式求值能力。

2.3 ForEachSqlNode:循环遍历

<foreach> 是最复杂的 SqlNode,因为它要处理:

  • 遍历集合参数
  • 生成占位符(#{item} → ?
  • 处理 opencloseseparator
  • 处理 index 和 item 变量
publicclassForEachSqlNodeimplementsSqlNode{
publicstaticfinal String ITEM_PREFIX = "__frch_";
privatefinal ExpressionEvaluator evaluator;
privatefinal String collectionExpression;
privatefinal SqlNode contents;
privatefinal String open;
privatefinal String close;
privatefinal String separator;
privatefinal String item;
privatefinal String index;
privatefinal Configuration configuration;

@Override
publicbooleanapply(DynamicContext context){
        Map<String, Object> bindings =
            context.getBindings();
final Iterable<?> iterable = evaluator
            .evaluateIterable(collectionExpression,
                bindings);
if (!iterable.iterator().hasNext()) {
returntrue;
        }
boolean first = true;
        applyOpen(context);
int i = 0;
for (Object o : iterable) {
            DynamicContext oldContext = context;
if (first || separator == null) {
                first = false;
            } else {
                context.appendSql(separator);
            }
// 创建新的上下文,绑定 item 和 index 变量
            context = new PrefixedContext(context, "");
if (index != null) {
                context.bind(index, o);
                context.bind(
                    itemizeItem(index, i), o);
            }
            context.bind(item, o);
            context.bind(
                itemizeItem(item, i), o);
// 执行子节点
            contents.apply(new FilteredDynamicContext(
                configuration, oldContext,
                itemizeItem(item, i),
                itemizeItem(index, i)));
            i++;
        }
        applyClose(context);
returntrue;
    }

privatestatic String itemizeItem(String item, int i){
return ITEM_PREFIX + item + "_" + i;
    }
}

<foreach> 的处理流程:

  1. 用 OGNL 从参数里取出集合(比如 listarrayuser.ids
  2. 如果集合为空,返回 true(不生成内容,但也不算失败)
  3. 遍历集合,每次迭代:
    • 追加 separator(除了第一次)
    • 绑定 item 变量到上下文(比如 item → 当前元素
    • 生成唯一的参数名(__frch_item_0__frch_item_1……)
    • 执行子节点(通常是 StaticTextSqlNode,内容如 #{item}
  4. 追加 open 和 close

__frch_ 前缀的参数名是为了避免冲突。<foreach> 展开后,每个元素对应一个独立的参数名,最终由 ParameterHandler 逐个绑定。

比如:

<foreachcollection="ids"item="id"open="("separator=","close=")">
    #{id}
</foreach>

传入 ids = [1, 2, 3],解析后生成:

( ? , ? , ? )

同时 DynamicContext 里的参数绑定变成:

__frch_id_0 → 1
__frch_id_1 → 2
__frch_id_2 → 3

2.4 TrimSqlNode / WhereSqlNode / SetSqlNode:修剪器

<where> 和 <set> 底层都是 TrimSqlNode,只是预设了不同的前缀/后缀规则。

publicclassTrimSqlNodeimplementsSqlNode{
privatefinal SqlNode contents;
privatefinal String prefix;
privatefinal String suffix;
privatefinal List<String> prefixesToOverride;
privatefinal List<String> suffixesToOverride;

@Override
publicbooleanapply(DynamicContext context){
// 创建过滤上下文
        FilteredDynamicContext filteredDynamicContext =
new FilteredDynamicContext(context);
// 执行子节点,内容写入 filteredDynamicContext
boolean result = contents.apply(filteredDynamicContext);
// 处理前缀/后缀修剪
        filteredDynamicContext.applyAll();
return result;
    }
}

TrimSqlNode 的工作方式:

  1. 创建 FilteredDynamicContext,子节点先把 SQL 片段写到这里
  2. 子节点执行完后,检查内容的开头是否有 prefixesToOverride 里定义的字符串(比如 ANDOR),如果有,去掉
  3. 检查末尾是否有 suffixesToOverride,如果有,去掉
  4. 追加 prefix(比如 WHERE)和 suffix

<where> 的定义:

publicclassWhereSqlNodeextendsTrimSqlNode{
publicWhereSqlNode(Configuration configuration,
            SqlNode contents)
{
super(configuration, contents, "WHERE",
            Arrays.asList("AND ""AND\n""OR ""OR\n"),
nullnull);
    }
}
  • 前缀:WHERE
  • 要去掉的前缀:ANDOR(带空格和换行)
  • 没有后缀处理

这就是为什么 <where> 能自动处理多余的 AND/OR:子节点生成的内容可能是 AND name = ?TrimSqlNode 会把开头的 AND 去掉,然后加上 WHERE

三、DynamicContext:SQL 拼接的上下文

DynamicContext 是动态 SQL 解析的上下文,负责两件事:

  1. 拼接 SQL 字符串 —— 用 StringBuilder 累积 SQL 片段
  2. 管理参数绑定 —— 存储 OGNL 表达式能访问的变量
publicclassDynamicContext{
privatefinal StringBuilder sqlBuilder = new StringBuilder();
privatefinal Map<String, Object> bindings = new HashMap<>();
privatefinal MetaObject parameterMetaObject;

publicDynamicContext(Configuration configuration,
            Object parameterObject)
{
if (parameterObject != null) {
if (parameterObject instanceof Map) {
// Map 参数直接放进 bindings
                bindings.putAll((Map<?, ?>) parameterObject);
            }
// 创建 MetaObject,让 OGNL 可以访问属性
            parameterMetaObject = configuration
                .newMetaObject(parameterObject);
        }
// _parameter 指向参数对象本身
        bindings.put("_parameter", parameterObject);
// _databaseId 指向当前数据库标识
        bindings.put("_databaseId",
            configuration.getDatabaseId());
    }

publicvoidbind(String name, Object value){
        bindings.put(name, value);
    }

publicvoidappendSql(String sql){
        sqlBuilder.append(sql);
        sqlBuilder.append(" ");
    }

public String getSql(){
return sqlBuilder.toString().trim();
    }

public Map<String, Object> getBindings(){
return bindings;
    }
}

bindings 是 OGNL 表达式的变量上下文。parameterMetaObject 让 OGNL 可以通过属性名访问对象(比如 user.name)。

_parameter 和 _databaseId 是内置变量:

  • _parameter —— 当前参数对象
  • _databaseId —— 当前数据库标识(多数据库支持时用)

四、从 SqlNode 到 BoundSql:完整解析流程

动态 SQL 的执行分两步:

4.1 第一步:SqlNode.apply() → 拼接 SQL 文本

// DynamicSqlSource.getBoundSql()
public BoundSql getBoundSql(Object parameterObject){
// 1. 创建上下文
    DynamicContext context = new DynamicContext(
        configuration, parameterObject);
// 2. SqlNode 树解析,生成 SQL 文本
    rootSqlNode.apply(context);
// 3. 处理 #{ } 占位符
    SqlSourceBuilder sqlSourceParser =
new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null
        ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(
        context.getSql(), parameterType,
        context.getBindings());
// 4. 生成最终的 BoundSql
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
// 5. 把 <bind> 产生的额外参数也放进 BoundSql
for (Map.Entry<String, Object> entry
            : context.getBindings().entrySet()) {
        boundSql.setAdditionalParameter(
            entry.getKey(), entry.getValue());
    }
return boundSql;
}

4.2 第二步:SqlSourceBuilder.parse() → 处理 #{ }

SqlNode 解析完后,SQL 里可能还有 #{name} 占位符。SqlSourceBuilder 负责把它们替换成 ?,并生成 ParameterMapping

public SqlSource parse(String originalSql,
        Class<?> parameterType,
        Map<String, Object> additionalParameters)
{
    ParameterMappingTokenHandler handler =
new ParameterMappingTokenHandler(
            configuration, parameterType,
            additionalParameters);
    GenericTokenParser parser = new GenericTokenParser(
"#{""}", handler);
    String sql = parser.parse(originalSql);
returnnew StaticSqlSource(configuration, sql,
        handler.getParameterMappings());
}

GenericTokenParser 是个通用占位符解析器:

public String parse(String text){
    StringBuilder builder = new StringBuilder();
if (text != null && text.length() > 0) {
char[] src = text.toCharArray();
int offset = 0;
int start = text.indexOf(openToken, offset);
while (start > -1) {
int end = text.indexOf(closeToken, start);
if (end > -1) {
// 提取 #{ } 里的内容
                String content = text.substring(
                    start + openToken.length(), end);
// 交给 handler 处理
                builder.append(handler.handleToken(content));
                offset = end + closeToken.length();
                start = text.indexOf(openToken, offset);
            } else {
                builder.append(src, start, src.length - start);
break;
            }
        }
if (offset < src.length) {
            builder.append(src, offset,
                src.length - offset);
        }
    }
return builder.toString();
}

ParameterMappingTokenHandler.handleToken()

@Override
public String handleToken(String content){
    parameterMappings.add(
        buildParameterMapping(content));
return"?";
}

把 #{name, jdbcType=VARCHAR} 解析成 ParameterMapping(包含属性名、JdbcType、TypeHandler),然后替换成 ?

4.3 最终产物:BoundSql

publicclassBoundSql{
privatefinal String sql;                    // 带 ? 的 SQL
privatefinal List<ParameterMapping> parameterMappings;
privatefinal Object parameterObject;        // 原始参数
privatefinal Map<String, Object> additionalParameters; // <foreach>、<bind> 产生的额外参数
privatefinal MetaObject metaParameters;     // 额外参数的 MetaObject
}

BoundSql 是 SQL 执行的最终产物:

  • sql:完整的 SQL 语句,所有 #{ } 已替换为 ?
  • parameterMappings:按顺序排列的参数映射,每个对应一个 ?
  • parameterObject:原始参数对象
  • additionalParameters<foreach> 产生的 __frch_xxx 参数、<bind> 产生的变量

五、${} vs #{}:为什么一个能注入,一个不能

这是面试经典题。从源码角度看,区别很明显:

  • **#{}**:在 SqlSourceBuilder.parse() 阶段被替换成 ?,然后用 PreparedStatement.setXxx() 设置参数。参数值不参与 SQL 拼接,完全交给 JDBC 处理,天然防注入。
  • **${}**:在 DynamicSqlSource 阶段直接字符串替换,参数值拼接到 SQL 里。如果参数来自用户输入且未过滤,就能注入。
// ${} 的处理在 TextSqlNode 里
publicclassTextSqlNodeimplementsSqlNode{
privatefinal String text;

@Override
publicbooleanapply(DynamicContext context){
// 创建 GenericTokenParser,解析 ${ }
        GenericTokenParser parser = new GenericTokenParser(
"${""}"new BindingTokenParser(context));
        context.appendSql(parser.parse(text));
returntrue;
    }
}

BindingTokenParser 直接用 OGNL 取值,然后 toString() 拼到 SQL 里。没有预编译,没有参数绑定,就是纯字符串替换。

这就像两扇门的区别:

  • #{} 是安检门——你先报身份(参数),保安查完才让你进(设置参数)
  • `${}`` 是敞开的大门——你说什么就是什么,直接进(字符串拼接),坏人也能混进来

所以 ${} 只能用于确定安全的场景,比如动态表名、列名、排序字段。用户输入的内容绝对不能用 ${}

六、完整流程回顾

Mapper XML 中的 <select>
    │
    ▼
XMLLanguageDriver.createSqlSource()
    │
    ▼
XMLScriptBuilder.parseScriptNode()
    │
    ├── parseDynamicTags() —— 递归解析 XML,生成 SqlNode 树
    │       ├── 静态文本 → StaticTextSqlNode
    │       ├── <if> → IfSqlNode(含子 SqlNode)
    │       ├── <foreach> → ForEachSqlNode(含子 SqlNode)
    │       ├── <where> → WhereSqlNode(TrimSqlNode 子类)
    │       └── ...
    │
    ├── 标记 isDynamic
    └── 返回 DynamicSqlSource(动态)或 RawSqlSource(静态)
    │
    ▼
执行查询时:DynamicSqlSource.getBoundSql(parameterObject)
    │
    ├── new DynamicContext(configuration, parameterObject)
    │
    ├── rootSqlNode.apply(context) —— 递归解析 SqlNode 树
    │       ├── MixedSqlNode.apply() → 遍历子节点
    │       ├── IfSqlNode.apply() → OGNL 求值 → true 则执行子节点
    │       ├── ForEachSqlNode.apply() → 遍历集合 → 生成 __frch_xxx 参数
    │       ├── TrimSqlNode.apply() → 子节点执行 → 修剪前缀/后缀
    │       └── StaticTextSqlNode.apply() → 追加文本到 context.sqlBuilder
    │
    ├── context.getSql() —— 拿到拼接后的 SQL 文本(可能含 #{ })
    │
    ├── SqlSourceBuilder.parse() —— 处理 #{ } 占位符
    │       ├── GenericTokenParser 逐个提取 #{ } 内容
    │       ├── 生成 ParameterMapping
    │       └── 替换成 ?
    │
    ├── new StaticSqlSource(sql, parameterMappings)
    └── sqlSource.getBoundSql(parameterObject) → 返回 BoundSql

七、几个常见疑问

为什么 <where> 能自动去掉开头的 AND,但 <trim> 更灵活?

<where> 是 <trim> 的特化版本,预设了 prefix="WHERE" 和 prefixesToOverride="AND | OR"。如果你需要更复杂的前缀/后缀处理(比如 SET 要去掉末尾逗号),直接用 <trim>

<foreach> 的 collection 里可以写什么?

可以是:

  • 参数名(如 idsuser.ids
  • OGNL 表达式(如 user.dept.ids
  • 内置变量(如 arraylist,当参数是数组或 List 时)

<bind> 是怎么工作的?

<bind> 在解析阶段用 OGNL 计算表达式,把结果绑定到 DynamicContext 的变量里。比如:

<bindname="pattern"value="'%' + name + '%'"/>
<where>
<iftest="name != null">
        AND name LIKE #{pattern}
</if>
</where>

pattern 会被计算成 %xxx%,然后绑定到 context.bindings,最终作为额外参数参与 ParameterHandler 的设置。

下篇预告

下一篇讲事务管理——JdbcTransaction 和 ManagedTransaction 有什么区别?MyBatis 和 Spring 集成后,事务到底是谁在管?这也是面试常问的问题。


本系列文章基于 MyBatis 3.5.x 源码,写作时对照源码逐行验证。如果发现有问题的地方,欢迎指正。

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-08 22:10:10 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/824023.html
  2. 运行时间 : 0.194875s [ 吞吐率:5.13req/s ] 内存消耗:4,703.34kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=954c2b24d86126a966cc3acf1fdf3380
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 4.22 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.11 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000919s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001315s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000693s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000584s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001377s ]
  6. SELECT * FROM `set` [ RunTime:0.000590s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001404s ]
  8. SELECT * FROM `article` WHERE `id` = 824023 LIMIT 1 [ RunTime:0.001150s ]
  9. UPDATE `article` SET `lasttime` = 1786198211 WHERE `id` = 824023 [ RunTime:0.001412s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000623s ]
  11. SELECT * FROM `article` WHERE `id` < 824023 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001027s ]
  12. SELECT * FROM `article` WHERE `id` > 824023 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001030s ]
  13. SELECT * FROM `article` WHERE `id` < 824023 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001568s ]
  14. SELECT * FROM `article` WHERE `id` < 824023 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001828s ]
  15. SELECT * FROM `article` WHERE `id` < 824023 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001599s ]
0.198640s