做直播网站软件有哪些软件,住房及城乡建设部信息中心网站,google谷歌搜索主页,云购系统商城网站建设在工作中#xff0c;往往有这样的需求#xff0c;对于同一个sql条件查询#xff0c;首先需要统计记录条数#xff0c;用以计算pageCount#xff0c;然后再对结果进行分页查询显示#xff0c;看下面一个例子。sql idstudentProperties!--sql片段-…在工作中往往有这样的需求对于同一个sql条件查询首先需要统计记录条数用以计算pageCount然后再对结果进行分页查询显示看下面一个例子。sql idstudentProperties!--sql片段--select stud_id as studId, name, email, dob, phonefrom students/sqlselect idcountAll resultTypeintselect count(1) from (include refidstudentProperties/include!--复用--) tmp/selectselect idfindAll resultTypeStudent parameterTypemapselect * from (include refidstudentProperties/include!--复用--) tmp limit #{offset}, #{pagesize}/select这就是sqlFragment它可以为select|insert|update|delete标签服务可以定义很多sqlFragment然后使用include标签引入多个sqlFragment。在工作中也是比较常用的一个功能它的优点很明显复用sql片段它的缺点也很明显不能完整的展现sql逻辑如果一个标签include了四至五个sqlFragment其可读性就非常差了。sqlFragment里的内容是可以随意写的它不需要是一个完整的sql它可以是“,phone”这么简单的文本。1.sqlFragment的解析过程sqlFragment存储于Configuration内部。protected final MapString, XNode sqlFragments new StrictMapXNode(XML fragments parsed from previous mappers);解析sqlFragment的过程非常简单。org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XNode)方法部分源码。// 解析sqlFragment
sqlElement(context.evalNodes(/mapper/sql));
// 为select|insert|update|delete提供服务
buildStatementFromContext(context.evalNodes(select|insert|update|delete));sqlFragment存储于MapString, XNode结构当中。其实最关键的是它如何为select|insert|update|delete提供服务的。2.select|insert|update|delete标签中解析include标签的过程org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode()方法源码。// Include Fragments before parsing
XMLIncludeTransformer includeParser new XMLIncludeTransformer(configuration, builderAssistant);
// 重点关注的方法
includeParser.applyIncludes(context.getNode());// Parse selectKey after includes and remove them.
processSelectKeyNodes(id, parameterTypeClass, langDriver);// Parse the SQL (pre: selectKey and include were parsed and removed)
SqlSource sqlSource langDriver.createSqlSource(configuration, context, parameterTypeClass);注释“pre: selectKey and include were parsed and removed”含义为解析完并移除。为什么要移除呢秘密都隐藏在applyIncludes()方法内部了。org.apache.ibatis.builder.xml.XMLIncludeTransformer.applyIncludes(Node, Properties)方法源码。/*** Recursively apply includes through all SQL fragments.* param source Include node in DOM tree* param variablesContext Current context for static variables with values*/private void applyIncludes(Node source, final Properties variablesContext) {if (source.getNodeName().equals(include)) {// new full context for included SQL - contains inherited context and new variables from current include nodeProperties fullContext;String refid getStringAttribute(source, refid);// replace variables in include refid valuerefid PropertyParser.parse(refid, variablesContext);Node toInclude findSqlFragment(refid);Properties newVariablesContext getVariablesContext(source, variablesContext);if (!newVariablesContext.isEmpty()) {// merge contextsfullContext new Properties();fullContext.putAll(variablesContext);fullContext.putAll(newVariablesContext);} else {// no new context - use inherited fullyfullContext variablesContext;}// 递归调用applyIncludes(toInclude, fullContext);if (toInclude.getOwnerDocument() ! source.getOwnerDocument()) {toInclude source.getOwnerDocument().importNode(toInclude, true);}// 将include节点替换为sqlFragment节点source.getParentNode().replaceChild(toInclude, source);while (toInclude.hasChildNodes()) {// 将sqlFragment的子节点也就是文本节点插入到sqlFragment的前面toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);}// 移除sqlFragment节点toInclude.getParentNode().removeChild(toInclude);} else if (source.getNodeType() Node.ELEMENT_NODE) {NodeList children source.getChildNodes();for (int i0; ichildren.getLength(); i) {// 递归调用applyIncludes(children.item(i), variablesContext);}} else if (source.getNodeType() Node.ATTRIBUTE_NODE !variablesContext.isEmpty()) {// replace variables in all attribute valuessource.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));} else if (source.getNodeType() Node.TEXT_NODE !variablesContext.isEmpty()) {// replace variables ins all text nodessource.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));}}上面是对源码的解读为了便于理解我们接下来采用图示的办法演示其过程。3.图示过程演示①解析节点select idcountAll resultTypeintselect count(1) from (include refidstudentProperties/include) tmp/select②include节点替换为sqlFragment节点select idcountAll resultTypeintselect count(1) from (sql idstudentPropertiesselect stud_id as studId, name, email, dob, phonefrom students/sql
) tmp/select③将sqlFragment的子节点文本节点insert到sqlFragment节点的前面。注意对于dom来说文本也是一个节点叫TextNode。select idcountAll resultTypeintselect count(1) from (select stud_id as studId, name, email, dob, phonefrom studentssql idstudentPropertiesselect stud_id as studId, name, email, dob, phonefrom students/sql
) tmp/select④移除sqlFragment节点select idcountAll resultTypeintselect count(1) from (select stud_id as studId, name, email, dob, phonefrom students
) tmp/select⑤最终结果如图所示如此一来TextNode1 TextNode2 TextNode3就组成了一个完整的sql。遍历select的三个子节点分别取出TextNode的valueappend到一起就是最终完整的sql。这也是为什么要移除selectKey and include节点的原因。这就是Mybatis的sqlFragment以上示例均为静态sql即static sql。最后感谢大家看到最后如文章有不足欢迎大家在评论区支持给予意见。如果觉得我的文章对你有帮助那就给我一个赞同吧。每天都会分享java相关技术文章或行业资讯。欢迎大家关注和转发文章。