一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

動(dòng)態(tài)Sql介紹

Android編程精選 ? 來(lái)源:Android編程精選 ? 2023-05-31 09:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

動(dòng)態(tài)Sql介紹

動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一。如果你使用過(guò) JDBC 或其它類似的框架,你應(yīng)該能理解根據(jù)不同條件拼接 SQL 語(yǔ)句有多痛苦,例如拼接時(shí)要確保不能忘記添加必要的空格,還要注意去掉列表最后一個(gè)列名的逗號(hào)。利用動(dòng)態(tài) SQL,可以徹底擺脫這種痛苦。

使用動(dòng)態(tài) SQL 并非一件易事,但借助可用于任何 SQL 映射語(yǔ)句中的強(qiáng)大的動(dòng)態(tài) SQL 語(yǔ)言,MyBatis 顯著地提升了這一特性的易用性。

Mybatis動(dòng)態(tài)解析里面有2個(gè)核心的類SqlNode、SqlSource、ExpressionEvaluator。Mybatis動(dòng)態(tài)Sql使用分為2個(gè)部分:動(dòng)態(tài)Sql解析、動(dòng)態(tài)Sql拼接執(zhí)行。

封裝SqlNode

SqlNode是在解析Xml文件的時(shí)候?qū)?dòng)態(tài)Sql進(jìn)行解析,并存在MappedStatement的sqlSource屬性中。對(duì)于嵌套動(dòng)態(tài)Sql,mybatis用遞歸調(diào)用來(lái)進(jìn)行解析。這塊東西個(gè)人覺(jué)得還是比較繞,所以這塊博主準(zhǔn)備事例、源碼、執(zhí)行結(jié)果一起講解。

Sql腳本分類

在Mybatis中Sql腳本分為2種類型:靜態(tài)Sql和動(dòng)態(tài)Sql。下面我們通過(guò)具體的源碼來(lái)看下2者區(qū)分。

靜態(tài)Sql和動(dòng)態(tài)Sql

靜態(tài)Sql說(shuō)白了就沒(méi)有太任何判斷了解的Sql腳本。

//Select是查詢的一些屬性

//這條查詢語(yǔ)句select*fromuserwhereid>#{user.id}就是Mybatis中的靜態(tài)Sql
//靜態(tài)Sql就是不太任何條件的Sql語(yǔ)句
select*fromuserwhereid>#{user.id}
//這里有if判斷條件,Mybatis把帶有判斷條件的Sql叫動(dòng)態(tài)Sql。
//動(dòng)態(tài)Sql除了if之外還有foreach、where、trim等。具體自己去mybatis官網(wǎng)看下

ANDname=#{user.name}


SqlNode類結(jié)果體系

f201471e-ff21-11ed-90ce-dac502259ad0.png

看mybatis代碼很多時(shí)候可以看到這種結(jié)構(gòu)。每個(gè)SqlNode負(fù)責(zé)自己那塊功能。職責(zé)單一。SqlNode的核心方法apply就是通過(guò)ExpressionEvaluator來(lái)解析OGNL表達(dá)式數(shù)據(jù)的。接下來(lái)我們看看Mybatis是如何遞歸解析動(dòng)態(tài)sql腳本的。

//解析Sql腳本節(jié)點(diǎn)
publicSqlSourceparseScriptNode(){
//解析靜態(tài)和動(dòng)態(tài)腳本,并存在MixedSqlNode里面
//這行代碼很關(guān)鍵,后面我們會(huì)去分析parseDynamicTags這里就是一層一層遞歸調(diào)用該方法把Sql腳本生成MixedSqlNode對(duì)象。
MixedSqlNoderootSqlNode=parseDynamicTags(context);
SqlSourcesqlSource=null;
//是否為動(dòng)態(tài)Sql
if(isDynamic){
//動(dòng)態(tài)Sql則生成DynamicSqlSource
sqlSource=newDynamicSqlSource(configuration,rootSqlNode);
}else{
//否則為靜態(tài)SqlSource
sqlSource=newRawSqlSource(configuration,rootSqlNode,parameterType);
}
returnsqlSource;
}
//Anhighlightedblock
protectedMixedSqlNodeparseDynamicTags(XNodenode){
//創(chuàng)建個(gè)SqlNode,這個(gè)列表存了當(dāng)前Sql腳本節(jié)點(diǎn)下的所有的SqlNode信息
Listcontents=newArrayList();
NodeListchildren=node.getNode().getChildNodes();
for(inti=0;iinSQLstatement.");
}
//調(diào)用對(duì)應(yīng)的handler進(jìn)行節(jié)點(diǎn)處理,遞歸調(diào)用就在這塊
handler.handleNode(child,contents);
isDynamic=true;
}
}
//創(chuàng)建MixedSqlNode
returnnewMixedSqlNode(contents);
}
//下面我們看下IfHandler是如何處理,IfHandler是XMLScriptBuilder的內(nèi)部類
privateclassIfHandlerimplementsNodeHandler{
publicIfHandler(){
//PreventSyntheticAccess
}
//我們著重分析這個(gè)方法
@Override
publicvoidhandleNode(XNodenodeToHandle,ListtargetContents){
//調(diào)用parseDynamicTags進(jìn)行節(jié)點(diǎn)解析。這里就是遞歸,又調(diào)用了上面的方法。
MixedSqlNodemixedSqlNode=parseDynamicTags(nodeToHandle);
//獲取if對(duì)應(yīng)的表達(dá)式
Stringtest=nodeToHandle.getStringAttribute("test");
//創(chuàng)建IfSqlNode
IfSqlNodeifSqlNode=newIfSqlNode(mixedSqlNode,test);
targetContents.add(ifSqlNode);
}
}

下面我們根據(jù)Sql腳本和執(zhí)行結(jié)果來(lái)分析。

//靜態(tài)Sql腳本和嵌套的動(dòng)態(tài)Sql腳本

select*fromuserwhereid>#{user.id}

ANDname=#{user.name}

ANDname=#{user.name}

ANDname=#{user.name}




下面我們分析下執(zhí)行結(jié)果:

f214e24c-ff21-11ed-90ce-dac502259ad0.png

上面遞歸結(jié)果已經(jīng)用不通顏色標(biāo)記了,大家自己看下。特別需要看下IfSqlNode的屬性。

動(dòng)態(tài)Sql解析

動(dòng)態(tài)Sql解析主要是執(zhí)行數(shù)據(jù)庫(kù)操作的時(shí)候把動(dòng)態(tài)Sql轉(zhuǎn)換成JDBC能識(shí)別的Sql腳本。Mybatis中主要是通過(guò)SqlSource來(lái)解析Sql腳本,替換成JDBC能識(shí)別的Sql腳本。我們先看下類圖。

f25b2838-ff21-11ed-90ce-dac502259ad0.png

SqlSource:提供了Sql解析的行為。
RawSqlSource:靜態(tài)Sql腳本的編譯,只生成一次StaticSqlSource。
DynamicSqlSource:每次調(diào)用都會(huì)生成StaticSqlSource。每次調(diào)用傳入?yún)?shù)可能不一樣。需要每次生成StaticSqlSource。
ProviderSqlSource:第三方腳本語(yǔ)言的集成。
FreeMarkerSqlSource:對(duì)FreeMarker的支持。
StaticSqlSource:StaticSqlSource只是對(duì)上面4中類型做了層封裝。博主沒(méi)有這個(gè)類會(huì)更清爽些。
我們這次主要對(duì)StaticSqlSource、RawSqlSource、和DynamicSqlSource進(jìn)行分析。

StaticSqlSource

其實(shí)StaticSqlSource就是對(duì)其他幾種類型Sql處理器結(jié)果進(jìn)行包裝。我們看下源碼。

//我們主要分析下getBoundSql
publicclassStaticSqlSourceimplementsSqlSource{

privatefinalStringsql;
privatefinalListparameterMappings;
privatefinalConfigurationconfiguration;

publicStaticSqlSource(Configurationconfiguration,Stringsql){
this(configuration,sql,null);
}

publicStaticSqlSource(Configurationconfiguration,Stringsql,ListparameterMappings){
this.sql=sql;
this.parameterMappings=parameterMappings;
this.configuration=configuration;
}

//getBoundSql就是創(chuàng)建一個(gè)BoundSql對(duì)象。
@Override
publicBoundSqlgetBoundSql(ObjectparameterObject){
returnnewBoundSql(configuration,sql,parameterMappings,parameterObject);
}

}

看完是不是非常簡(jiǎn)單,其實(shí)有些代碼確實(shí)沒(méi)有我們想象中那么難。

RawSqlSource

//我們著重分析RawSqlSource方法
publicclassRawSqlSourceimplementsSqlSource{

privatefinalSqlSourcesqlSource;

publicRawSqlSource(Configurationconfiguration,SqlNoderootSqlNode,ClassparameterType){
this(configuration,getSql(configuration,rootSqlNode),parameterType);
}
//這里實(shí)現(xiàn)了對(duì)靜態(tài)腳本的解析,所謂的靜態(tài)腳本解析就是把#{}解析成?靜態(tài)Sql解析是在解析Mapper.xml的時(shí)候執(zhí)行的
publicRawSqlSource(Configurationconfiguration,Stringsql,ClassparameterType){
SqlSourceBuildersqlSourceParser=newSqlSourceBuilder(configuration);
Classclazz=parameterType==null?Object.class:parameterType;
//通過(guò)調(diào)用SqlSourceBuilder的parse方法來(lái)解析Sql
sqlSource=sqlSourceParser.parse(sql,clazz,newHashMap());
}

privatestaticStringgetSql(Configurationconfiguration,SqlNoderootSqlNode){
DynamicContextcontext=newDynamicContext(configuration,null);
rootSqlNode.apply(context);
returncontext.getSql();
}

@Override
publicBoundSqlgetBoundSql(ObjectparameterObject){
returnsqlSource.getBoundSql(parameterObject);
}

}

下面我們來(lái)看下SqlSourceBuilder的parse方法

publicSqlSourceparse(StringoriginalSql,ClassparameterType,MapadditionalParameters){
ParameterMappingTokenHandlerhandler=newParameterMappingTokenHandler(configuration,parameterType,additionalParameters);
//找到Sql腳本中#{}符號(hào)的腳本用?號(hào)進(jìn)行替代。GenericTokenParser里面代碼比較復(fù)雜,博主也沒(méi)有研究。
//有興趣自己可以研究下。
GenericTokenParserparser=newGenericTokenParser("#{","}",handler);
Stringsql=parser.parse(originalSql);
returnnewStaticSqlSource(configuration,sql,handler.getParameterMappings());
}

DynamicSqlSource

動(dòng)態(tài)Sql解析主要由DynamicSqlSource來(lái)完成。這里面又是通過(guò)遞歸調(diào)進(jìn)行sql解析。我們還是延用上面的Sql給大家講解。

publicclassDynamicSqlSourceimplementsSqlSource{

privatefinalConfigurationconfiguration;
privatefinalSqlNoderootSqlNode;

publicDynamicSqlSource(Configurationconfiguration,SqlNoderootSqlNode){
this.configuration=configuration;
this.rootSqlNode=rootSqlNode;
}

@Override
publicBoundSqlgetBoundSql(ObjectparameterObject){
//動(dòng)態(tài)Sql解析上下文
DynamicContextcontext=newDynamicContext(configuration,parameterObject);
//rootSqlNode就是我們前面講解的,把動(dòng)態(tài)Sql解析成SqlNode對(duì)象。外層為MixedSqlNode節(jié)點(diǎn),節(jié)點(diǎn)存儲(chǔ)了
//節(jié)點(diǎn)下的所有子節(jié)點(diǎn)。里面遞歸調(diào)用并根據(jù)傳入?yún)?shù)的屬性檢查是否需要拼接sql
rootSqlNode.apply(context);
//這塊代碼和上面靜態(tài)Sql接代碼一致。
SqlSourceBuildersqlSourceParser=newSqlSourceBuilder(configuration);
ClassparameterType=parameterObject==null?Object.class:parameterObject.getClass();
//把我們動(dòng)態(tài)Sql中的#{}替換成?
SqlSourcesqlSource=sqlSourceParser.parse(context.getSql(),parameterType,context.getBindings());
BoundSqlboundSql=sqlSource.getBoundSql(parameterObject);
for(Map.Entryentry:context.getBindings().entrySet()){
boundSql.setAdditionalParameter(entry.getKey(),entry.getValue());
}
returnboundSql;
}

}

動(dòng)態(tài)Sql解析apply方法博主只根據(jù)場(chǎng)景介紹下MixedSqlNode和IfSqlNode的apply方法。其他有興趣自己去研究下。邏輯大體一致,實(shí)現(xiàn)有些區(qū)別。

publicclassMixedSqlNodeimplementsSqlNode{
privatefinalListcontents;

publicMixedSqlNode(Listcontents){
this.contents=contents;
}

//獲取循環(huán)SqlNode列表的所有SqlNode,調(diào)用apply方法根據(jù)傳入?yún)?shù)和條件進(jìn)行靜態(tài)sql的拼接。
//列表中的SqlNode可能是一個(gè)簡(jiǎn)單的SqlNode對(duì)象,也可能是一個(gè)MixedSqlNode或者有更多的嵌套。
//博主的例子就是3個(gè)嵌套If查詢。根據(jù)博主的Sql腳本,這里直接會(huì)調(diào)用IfSqlNode的apply方法。
//我們接下來(lái)看下IfSqlNode是如何實(shí)現(xiàn)的。
@Override
publicbooleanapply(DynamicContextcontext){
for(SqlNodesqlNode:contents){
sqlNode.apply(context);
}
returntrue;
}
}

IfSqlNode的apply

publicclassIfSqlNodeimplementsSqlNode{
//ExpressionEvaluator會(huì)調(diào)用ognl來(lái)對(duì)表達(dá)式進(jìn)行解析
privatefinalExpressionEvaluatorevaluator;
privatefinalStringtest;
privatefinalSqlNodecontents;

publicIfSqlNode(SqlNodecontents,Stringtest){
this.test=test;
this.contents=contents;
this.evaluator=newExpressionEvaluator();
}

@Override
publicbooleanapply(DynamicContextcontext){
//context.getBindings()里面就存儲(chǔ)這請(qǐng)求參數(shù),這里是一個(gè)HashMap,OGNl里面代碼博主沒(méi)有研究。
//如果條件if成立,直接獲取contents中的SqlNode的apply方法進(jìn)行動(dòng)態(tài)腳本處理。
if(evaluator.evaluateBoolean(test,context.getBindings())){
contents.apply(context);
returntrue;
}
returnfalse;
}

}

這塊代碼很多遞歸調(diào)用,博主自認(rèn)為講的不太透徹,所以大家看完務(wù)必自己去調(diào)試下。

總結(jié)

Mybatis動(dòng)態(tài)Sql從解析到執(zhí)行分為2個(gè)過(guò)程下面對(duì)這個(gè)2個(gè)過(guò)程進(jìn)行簡(jiǎn)單總結(jié)。
1.動(dòng)態(tài)Sql生成SqlNode信息,這個(gè)過(guò)程發(fā)生在對(duì)select、update等Sql語(yǔ)句解析過(guò)程。如果是靜態(tài)Sql直接會(huì)把#{}替換成?。
2.動(dòng)態(tài)Sql解析在獲取BoundSql時(shí)候觸發(fā)。會(huì)調(diào)用SqlNode的apply進(jìn)行Sql解析成靜態(tài)Sql,然后把#{}替換成?,并綁定ParameterMapping映射。

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • SQL
    SQL
    +關(guān)注

    關(guān)注

    1

    文章

    783

    瀏覽量

    45122
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    671

    瀏覽量

    30321
  • 腳本
    +關(guān)注

    關(guān)注

    1

    文章

    398

    瀏覽量

    28453

原文標(biāo)題:Mybatis動(dòng)態(tài)Sql處理

文章出處:【微信號(hào):AndroidPush,微信公眾號(hào):Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    在Delphi中動(dòng)態(tài)地使用SQL查詢語(yǔ)句

    在Delphi中動(dòng)態(tài)地使用SQL查詢語(yǔ)句在一般的數(shù)據(jù)庫(kù)管理系統(tǒng)中,通常都需要應(yīng)用SQL查詢語(yǔ)句來(lái)提高程序的動(dòng)態(tài)特性。下面介紹如何在Delph
    發(fā)表于 05-10 11:10

    DRDS分布式SQL引擎—執(zhí)行計(jì)劃介紹

    摘要: 本文著重介紹 DRDS 執(zhí)行計(jì)劃中各個(gè)操作符的含義,以便用戶通過(guò)查詢計(jì)劃了解 SQL 執(zhí)行流程,從而有針對(duì)性的調(diào)優(yōu) SQL。DRDS分布式SQL引擎 — 執(zhí)行計(jì)劃
    發(fā)表于 07-12 17:01

    手寫SQL編譯器——文法介紹

    精讀《手寫 SQL 編譯器 - 文法介紹
    發(fā)表于 05-29 13:35

    為什么要動(dòng)態(tài)sql語(yǔ)句?

    為什么要動(dòng)態(tài)sql語(yǔ)句?因?yàn)?b class='flag-5'>動(dòng)態(tài)sql語(yǔ)句能夠提供一些比較友好的機(jī)制1、可以使得一些在編譯過(guò)程中無(wú)法獲得完整的sql語(yǔ)句,在程序執(zhí)行階段
    發(fā)表于 12-20 06:00

    基于數(shù)據(jù)窗口對(duì)象SQL 語(yǔ)法的動(dòng)態(tài)移植技術(shù)探討

    在PowerBuilder9.0 應(yīng)用程序中,動(dòng)態(tài)創(chuàng)建特定顯示風(fēng)格和結(jié)構(gòu)比較復(fù)雜的數(shù)據(jù)窗口對(duì)象是開(kāi)發(fā)人員所面臨的一大難題。文章就該問(wèn)題提出通過(guò)移植數(shù)據(jù)窗口對(duì)象SQL 語(yǔ)法的方法來(lái)實(shí)現(xiàn)
    發(fā)表于 05-30 10:29 ?11次下載

    Delphi教程之在SQL查詢中使用動(dòng)態(tài)參數(shù)

    Delphi教程之在SQL查詢中使用動(dòng)態(tài)參數(shù),學(xué)習(xí)Delphi的必備資料。
    發(fā)表于 03-31 11:29 ?4次下載

    SQL相關(guān)知識(shí)解析及SQL完全手冊(cè)的免費(fèi)分享

    本文介紹SQL的基礎(chǔ)知識(shí)、SQL快速入門及SQL編程手冊(cè)的分享。
    發(fā)表于 11-22 11:31 ?0次下載
    <b class='flag-5'>SQL</b>相關(guān)知識(shí)解析及<b class='flag-5'>SQL</b>完全手冊(cè)的免費(fèi)分享

    mybatis動(dòng)態(tài)sql詳解

    本文詳細(xì)介紹了mybatis執(zhí)行動(dòng)態(tài)sql語(yǔ)句的方法。
    發(fā)表于 02-24 11:37 ?3987次閱讀

    SQL教程之什么是SQL能做什么SQL基礎(chǔ)的詳細(xì)資料介紹

    SQL 是一門 ANSI 的標(biāo)準(zhǔn)計(jì)算機(jī)語(yǔ)言,用來(lái)訪問(wèn)和操作數(shù)據(jù)庫(kù)系統(tǒng).SQL 語(yǔ)句用于取回和更新數(shù)據(jù)庫(kù)中的數(shù)據(jù).SQL 可與數(shù)據(jù)庫(kù)程序協(xié)同工作,比如 MS Access、DB2、Informix、MS
    發(fā)表于 12-10 08:00 ?8次下載

    java的動(dòng)態(tài)SQL詳細(xì)資料說(shuō)明

    首先,所謂SQL動(dòng)態(tài)和靜態(tài),是指SQL語(yǔ)句在何時(shí)被編譯和執(zhí)行,二者都是用在SQL嵌入式編程中的,這里所說(shuō)的嵌入式是指將SQL語(yǔ)句嵌入在高級(jí)
    發(fā)表于 06-06 17:51 ?0次下載
    java的<b class='flag-5'>動(dòng)態(tài)</b><b class='flag-5'>SQL</b>詳細(xì)資料說(shuō)明

    SQL注入到Getshell的教程

    上一節(jié),我們已經(jīng)介紹了基本的SQL查詢語(yǔ)句,常見(jiàn)的SQL注入類型,DVWA靶場(chǎng)演示SQL注入。學(xué)習(xí)了上一節(jié)我們可以做到執(zhí)行任意SQL語(yǔ)句,主
    的頭像 發(fā)表于 09-21 14:45 ?3442次閱讀

    一文掌握MyBatis的動(dòng)態(tài)SQL使用與原理

    摘要:使用動(dòng)態(tài) SQL 并非一件易事,但借助可用于任何 SQL 映射語(yǔ)句中的強(qiáng)大的動(dòng)態(tài) SQL 語(yǔ)言,MyBatis 顯著地提升了這一特性的
    的頭像 發(fā)表于 01-06 11:27 ?1271次閱讀

    PROC SQL介紹

    SQL(Structured Query Language)——結(jié)構(gòu)化查詢語(yǔ)言,是用于檢索和更新數(shù)據(jù)的一種標(biāo)準(zhǔn)化語(yǔ)言,SQL在SAS中通過(guò)PROC SQL來(lái)實(shí)現(xiàn)。
    的頭像 發(fā)表于 05-19 16:10 ?3170次閱讀
    PROC <b class='flag-5'>SQL</b><b class='flag-5'>介紹</b>

    MyBatis動(dòng)態(tài)sql是什么?MyBatis動(dòng)態(tài)SQL最全教程

    動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一。在 JDBC 或其它類似的框架中,開(kāi)發(fā)人員通常需要手動(dòng)拼接 SQL 語(yǔ)句。根據(jù)不同的條件拼接 SQL 語(yǔ)句是一件極其痛苦的工作。
    的頭像 發(fā)表于 08-10 10:18 ?1238次閱讀

    oracle sql 定義變量并賦值

    在Oracle SQL中,變量是用來(lái)存儲(chǔ)數(shù)據(jù)值的標(biāo)識(shí)符。通過(guò)定義和使用變量,我們可以在SQL語(yǔ)句中使用它們來(lái)存儲(chǔ)和處理數(shù)據(jù),從而實(shí)現(xiàn)更靈活和動(dòng)態(tài)的查詢和操作。 在Oracle SQL
    的頭像 發(fā)表于 12-06 10:46 ?3614次閱讀