33、SQL解析基础
来源:互联网 发布:淘宝网主要特色 编辑:程序博客网 时间:2024/06/07 20:48
BoundSql
BoundSql只是一个简单的java对象,有两个属性比较重要
- sql:从解析时可以看出这个sql不是配置文件中的sql,这个sql已经经过了处理(如:占用位符的处理、动态语句的解析if、foreach等待)
- parameterObject:客户端执行sql时传入的参数
- parameterMappings: sql中的参数映射对应#{id,jdbcType=INTEGER}
标签sql对应的参数列表
字段
““java
public class BoundSql {
/** * 经过处理的sql,这个sql已经可以被数据库执行了 */private String sql;/** * sql中的参数映射对应#{id,jdbcType=INTEGER} */private List<ParameterMapping> parameterMappings;/** * 客户端执行sql时传入的参数 */private Object parameterObject;private Map<String, Object> additionalParameters;private MetaObject metaParameters;
}
““
SqlNode
java
public interface SqlNode {
boolean apply(DynamicContext context);
}
该方法的含义为,将sql的处理结果,append到DynamicContext context对象中,DynamicContext可以理解为StringBuilder对象的功能,它的作用就是计算sql片段并append到一起,形成最终的sql。
类似的实现还有whereSQLNode SetSqlNode ForEachSqlNode
等
VarDeclSqlNode
处理动态sql标签的SqlNode类。
@Override public boolean apply(DynamicContext context) { final Object value = OgnlCache.getValue(expression, context.getBindings()); // 由于没有sql可append,仅是把bind标签的变量名和值保存至上下文参数列表内 context.bind(name, value); return true; }
MixedSqlNode
意为混合的SqlNode,它保存了其他多种SqlNode的集合,可以看做是一个List列表
SqlNode的组合设计模式
SqlNode,采用了组合设计模式,组合设计模式可以用来表示经典的树型结构
前面说的MixedSqlNode,就代表了List集合
NodeHandler
SqlNode是由NodeHandler创建出来的。
private interface NodeHandler { void handleNode(XNode nodeToHandle, List<SqlNode> targetContents); }
BindHandler
用来生成VarDeclSqlNode
@Override public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) { final String name = nodeToHandle.getStringAttribute("name"); final String expression = nodeToHandle.getStringAttribute("value"); final VarDeclSqlNode node = new VarDeclSqlNode(name, expression); targetContents.add(node); }
TrimHandler
@Override public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) { List<SqlNode> contents = parseDynamicTags(nodeToHandle); MixedSqlNode mixedSqlNode = new MixedSqlNode(contents); String prefix = nodeToHandle.getStringAttribute("prefix"); String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides"); String suffix = nodeToHandle.getStringAttribute("suffix"); String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides"); TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides); targetContents.add(trim); }
ChooseHandler
@Override public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) { List<SqlNode> whenSqlNodes = new ArrayList<SqlNode>(); List<SqlNode> otherwiseSqlNodes = new ArrayList<SqlNode>(); handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes); SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes); ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode); targetContents.add(chooseSqlNode); } private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes, List<SqlNode> defaultSqlNodes) { List<XNode> children = chooseSqlNode.getChildren(); for (XNode child : children) { String nodeName = child.getNode().getNodeName(); NodeHandler handler = nodeHandlers(nodeName); if (handler instanceof IfHandler) { handler.handleNode(child, ifSqlNodes); } else if (handler instanceof OtherwiseHandler) { handler.handleNode(child, defaultSqlNodes); } } } private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) { SqlNode defaultSqlNode = null; if (defaultSqlNodes.size() == 1) { defaultSqlNode = defaultSqlNodes.get(0); } else if (defaultSqlNodes.size() > 1) { throw new BuilderException("Too many default (otherwise) elements in choose statement."); } return defaultSqlNode; }
可以清楚看出,标签是和、标签配合使用的,创建ChooseSqlNode时,就同时创建了when、otherwise的逻辑,而when会转换为if标签处理,otherwise则转换为SqlNode处理,一般是StaticTextSqlNode。
LanguageDriver
LanguageDriver是一个辅助工具类,用于创建SqlSource。
- XMLLanguageDriver:用于创建动态、静态SqlSource。
- RawLanguageDriver:在确保只有静态sql时,可以使用,不得含有任何动态sql的内容,否则,请使用XMLLanguageDriver。它其实是对XMLLanguageDriver创建的结果进行唯静态sql检查而已,发现有动态sql的内容,就抛异常。
DynamicContext
对传入的parameterObject进行map化,
字段
““java
public static final String PARAMETER_OBJECT_KEY = "_parameter";public static final String DATABASE_ID_KEY = "_databaseId";static { OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());}private final ContextMap bindings;private final StringBuilder sqlBuilder = new StringBuilder();private int uniqueNumber = 0;
““
ContextAccessor也是DynamicContext的内部类,实现了Ognl中的PropertyAccessor接口,为Ognl提供了如何使用ContextMap参数对象的说明
构造方法
public DynamicContext(Configuration configuration, Object parameterObject) { if (parameterObject != null && !(parameterObject instanceof Map)) {//如果参数是map MetaObject metaObject = configuration.newMetaObject(parameterObject); bindings = new ContextMap(metaObject); } else { bindings = new ContextMap(null); } bindings.put(PARAMETER_OBJECT_KEY, parameterObject); bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId()); }
在DynamicContext的构造函数中,可以看到,根据传入的参数对象是否为Map类型,有两个不同构造ContextMap的方式。而ContextMap作为一个继承了HashMap的对象,作用就是用于统一参数的访问方式:用Map接口方法来访问数据。具体来说,当传入的参数对象不是Map类型时,Mybatis会将传入的POJO对象用MetaObject对象来封装,当动态计算sql过程需要获取数据时,用Map接口的get方法包装 MetaObject对象的取值过程。
参数传递和使用过程
OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
将传入的参数对象统一封装为ContextMap对象(继承了HashMap对象),然后Ognl运行时环境在动态计算sql语句时,会按照ContextAccessor中描述的Map接口的方式来访问和读取ContextMap对象,获取计算过程中需要的参数。ContextMap对象内部可能封装了一个普通的POJO对象,也可以是直接传递的Map对象,当然从外部是看不出来的,因为都是使用Map的接口来读取数据。
sqlSource
在Mybatis中,每一个select|insert|update|delete标签,都会被解析为一个MappedStatement对象,SqlSource就是MappedStatement对象中一个属性,其最终执行的sql字符串就是由SqlSource提供的。
public interface SqlSource { BoundSql getBoundSql(Object parameterObject);}
sqlSource为一个接口,只有一个方法通过传入执行parameterObject参数返回BoundSql
sqlSource的实现有6中
sqlSource的实现
- DynamicSqlSource:处理动态sql。
- RawSqlSource:处理静态sql,其内部装饰StaticSqlSource。
- StaticSqlSource:处理静态sql,无论是静态sql,还是动态sql,最终的处理结果,都是静态sql。
- ProviderSqlSource:处理注解Annotation形式的sql。
DynamicSqlSource和StaticSqlSource的最大区别在于:StaticSqlSource的String sql,可以直接获取使用,而DynamicSqlSource的String sql需要逐一根据条件解析并拼接出最终的sql,方能使用。
DynamicSqlSource
DynamicSqlSource中的SqlNode rootSqlNode属性,通常都是MixedSqlNode对象(完全是静态sql时,可能是一个StaticTextSqlNode),而MixedSqlNode对象又保存了所有的List集合,这也是通过一个rootSqlNode,就能找到所有SqlNode的深层原因
- 33、SQL解析基础
- SQL server 基础语法语句大全 T-SQL解析
- sql解析
- SQL 解析
- SQL基础
- SQL基础
- SQL基础
- SQL 基础
- sql:基础
- SQL基础
- SQL基础
- SQL基础
- SQL基础
- SQL基础
- SQL 基础
- sql基础
- SQL基础
- sql基础
- 32、解析MetaObject
- Android基础--ListView的显示几种方式
- 1001. 求高精度幂
- 快速Android开发系列网络篇之Android-Async-Http
- 新的启程,新的进步。
- 33、SQL解析基础
- 《操作系统真象还原》-阅读笔记(中)
- 34、SqlSource解析
- Maven ProfileFilter 分环境运行
- 简单搜索poj 2243(水
- 35、MapperMethod映射器方法.
- mysql之 explain、optimizer_trace 执行计划
- “菜鱼”课设中的一道数据处理的题目(cpp)
- 日常 myeclipse链接VisualSVNServerShell 的错误