增删改查标签解析生成SQL过程
增删改查标签解析生成SQL过程
目录
一、将增删改查中的写的语句解析成SqlSource
对于xml中的每个增删改查的解析
来一个官方案例:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
首先需要将标签<增删改查>解析成多个SqlNode,然后将SqlNode转换成对应的SqlSource
这一步发生在org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode中的
/**
* 通过class org.apache.ibatis.scripting.xmltags.XMLLanguageDriver来解析我们的
* sql脚本对象 . 解析SqlNode. 注意, 只是解析成一个个的SqlNode, 并不会完全解析sql,因为这个时候参数都没确定,动态sql无法解析
*/
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
public SqlSource parseScriptNode() {
/**
* 递归解析-组合设计模式 selectById这个sql元素会解析成
* 1层 MixedSqlNode <SELECT>
* 2层 WhereSqlNode <WHERE>
* 3层 IfSqlNode <IF>
* test="条件表达式"
*
* contexts= sql语句分: 1.TextSqlNode 带${} 2.StaticTextSqlNode
*/
MixedSqlNode rootSqlNode = parseDynamicTags(context);
SqlSource sqlSource;
if (isDynamic) {
// 动态Sql源
// 动态Sql 就是还需要后续执行时根据传入参数动态解析Sql(因为有<if>等,还要拼接${}sql)
// 和参数ParameterMappings 也会在后续执行解析,因为动态条件肯定会有动态参数
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
// 静态Sql源 如果没有动态标签(<if>、<where>等) 以及 没有${} 就是静态Sql源
// 静态Sql 就是在这里就解析了Sql 和参数ParameterMappings 后续执行就不用解析了
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
// 其实他们的区别就是动态sql 需要在查询的时候解析 因为有动态sql 和拼接${}
// 静态sql 已经在这里确定好sql. 和参数ParameterMapping,
return sqlSource;
}
在这里分别生成DynamicSqlSource和RawSqlSource,最终生成SqlSource进行保存。
二、动态SqlSource的解析成BoundSQL
因为动态SqlSource的解析需要通过参数来确定具体的执行的是哪个SQL,所以参数需要发挥作用。
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取sql
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
对于查询来说:
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
public BoundSql getBoundSql(Object parameterObject) {
// 根据参数创建一个动态解析上下文
DynamicContext context = new DynamicContext(configuration, parameterObject);
// 1归 责任链 处理一个个SqlNode 编译出一个完整sql
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
// 2.接下来处理 处理sql中的#{...}
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
// 怎么处理呢? 很简单,就是拿到#{}中的内容 封装为parameterMapper, 替换成?
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
context.getBindings().forEach(boundSql::setAdditionalParameter);
return boundSql;
}
各种各样的标签解析,这里不做过多赘述。
三、完成的增删改查解析生成MappedStatement
上面只是针对
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
这里做了个解析,但是
从理论中来,到实践中去,最终回归理论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2021-09-04 java字符串之理论重点