聊聊Mybatis的动态Sql之SqlSource
Posted 周杰伦本人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊聊Mybatis的动态Sql之SqlSource相关的知识,希望对你有一定的参考价值。
聊聊Mybatis的动态Sql之SqlSource
构建SqlSource对象
当Mapper.xml的各个标签被解析后SqlNode,然后SqlSourceBuilder进一步处理,
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;
if (configuration.isShrinkWhitespacesInSql())
sql = parser.parse(removeExtraWhitespaces(originalSql));
else
sql = parser.parse(originalSql);
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
- ParameterMappingTokenHandler是静态内部类,它用来保存每个占位符参数解析后的结果
- 创建识别#占位符的解析器GenericTokenParser,解析sql,最终形成StaticSqlSource对象
SqlSource接口
SqlSource接口是用来创建被数据库执行的sql,它只有一个getBoundSql()方法
public interface SqlSource
BoundSql getBoundSql(Object parameterObject);
实现类有DynamicSqlSource、StaticSqlSource、RawSqlSource、ProviderSqlSource、VelocitySqlSource,这里重点说一下前三个实现类
解析动态Sql类
DynamicSqlSource是解析动态sql的类
public class DynamicSqlSource implements SqlSource
private final Configuration configuration;
private final SqlNode rootSqlNode;
public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode)
this.configuration = configuration;
this.rootSqlNode = rootSqlNode;
@Override
public BoundSql getBoundSql(Object parameterObject)
DynamicContext context = new DynamicContext(configuration, parameterObject);
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
context.getBindings().forEach(boundSql::setAdditionalParameter);
return boundSql;
它的getBoundSql()方法中:
- 创建DynamicContext对象
- 调用SqlNode的apply()方法完成对sql片段的解析
- 创建SqlSourceBuilder对象,调用parse()方法进行解析#,替换成?占位符,返回StaticSqlSource对象,
- 调用StaticSqlSource的getBoundSql()方法,返回BoundSql对象,这里存储着sql语句的相关信息
- 返回BoundSql对象
解析静态SQL类
RawSqlSource是解析静态sql文件的,在程序启动的时候就解析了
public class RawSqlSource implements SqlSource
private final SqlSource sqlSource;
public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType)
this(configuration, getSql(configuration, rootSqlNode), parameterType);
public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType)
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> clazz = parameterType == null ? Object.class : parameterType;
sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>());
private static String getSql(Configuration configuration, SqlNode rootSqlNode)
DynamicContext context = new DynamicContext(configuration, null);
rootSqlNode.apply(context);
return context.getSql();
@Override
public BoundSql getBoundSql(Object parameterObject)
return sqlSource.getBoundSql(parameterObject);
它的构造方法调用了getSql()方法,这个方法里调用SqlSource的apply()方法组装成完整sql,然后通过SqlSourceBuilder调用parse()方法处理#占位符,返回StaticSqlSource对象
StaticSqlSource
StaticSqlSource类:
public class StaticSqlSource implements SqlSource
@Override
public BoundSql getBoundSql(Object parameterObject)
return new BoundSql(configuration, sql, parameterMappings, parameterObject);
它的getBoundSql()方法就是创建BoundSql对象
总结
这篇文章讲了SqlSource的接口和它的几个实现类,其中DynamicSqlSource类和RawSqlSource类最最终生成StaticSqlSource类,由StaticSqlSource类调用getBoundSql()方法来创建BoundSql类,DynamicSqlSource是解析动态sql的类,RawSqlSource是解析静态sql的类,在程序启动的时候就生成sql了
以上是关于聊聊Mybatis的动态Sql之SqlSource的主要内容,如果未能解决你的问题,请参考以下文章