色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

動態Sql介紹

Android編程精選 ? 來源:Android編程精選 ? 2023-05-31 09:34 ? 次閱讀

動態Sql介紹

動態 SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最后一個列名的逗號。利用動態 SQL,可以徹底擺脫這種痛苦。

使用動態 SQL 并非一件易事,但借助可用于任何 SQL 映射語句中的強大的動態 SQL 語言,MyBatis 顯著地提升了這一特性的易用性。

Mybatis動態解析里面有2個核心的類SqlNode、SqlSource、ExpressionEvaluator。Mybatis動態Sql使用分為2個部分:動態Sql解析、動態Sql拼接執行。

封裝SqlNode

SqlNode是在解析Xml文件的時候對動態Sql進行解析,并存在MappedStatement的sqlSource屬性中。對于嵌套動態Sql,mybatis用遞歸調用來進行解析。這塊東西個人覺得還是比較繞,所以這塊博主準備事例、源碼、執行結果一起講解。

Sql腳本分類

在Mybatis中Sql腳本分為2種類型:靜態Sql和動態Sql。下面我們通過具體的源碼來看下2者區分。

靜態Sql和動態Sql

靜態Sql說白了就沒有太任何判斷了解的Sql腳本。

//Select是查詢的一些屬性

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

ANDname=#{user.name}


SqlNode類結果體系

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

看mybatis代碼很多時候可以看到這種結構。每個SqlNode負責自己那塊功能。職責單一。SqlNode的核心方法apply就是通過ExpressionEvaluator來解析OGNL表達式數據的。接下來我們看看Mybatis是如何遞歸解析動態sql腳本的。

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

下面我們根據Sql腳本和執行結果來分析。

//靜態Sql腳本和嵌套的動態Sql腳本

select*fromuserwhereid>#{user.id}

ANDname=#{user.name}

ANDname=#{user.name}

ANDname=#{user.name}




下面我們分析下執行結果:

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

上面遞歸結果已經用不通顏色標記了,大家自己看下。特別需要看下IfSqlNode的屬性。

動態Sql解析

動態Sql解析主要是執行數據庫操作的時候把動態Sql轉換成JDBC能識別的Sql腳本。Mybatis中主要是通過SqlSource來解析Sql腳本,替換成JDBC能識別的Sql腳本。我們先看下類圖。

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

SqlSource:提供了Sql解析的行為。
RawSqlSource:靜態Sql腳本的編譯,只生成一次StaticSqlSource。
DynamicSqlSource:每次調用都會生成StaticSqlSource。每次調用傳入參數可能不一樣。需要每次生成StaticSqlSource。
ProviderSqlSource:第三方腳本語言的集成。
FreeMarkerSqlSource:對FreeMarker的支持。
StaticSqlSource:StaticSqlSource只是對上面4中類型做了層封裝。博主沒有這個類會更清爽些。
我們這次主要對StaticSqlSource、RawSqlSource、和DynamicSqlSource進行分析。

StaticSqlSource

其實StaticSqlSource就是對其他幾種類型Sql處理器結果進行包裝。我們看下源碼。

//我們主要分析下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就是創建一個BoundSql對象。
@Override
publicBoundSqlgetBoundSql(ObjectparameterObject){
returnnewBoundSql(configuration,sql,parameterMappings,parameterObject);
}

}

看完是不是非常簡單,其實有些代碼確實沒有我們想象中那么難。

RawSqlSource

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

privatefinalSqlSourcesqlSource;

publicRawSqlSource(Configurationconfiguration,SqlNoderootSqlNode,ClassparameterType){
this(configuration,getSql(configuration,rootSqlNode),parameterType);
}
//這里實現了對靜態腳本的解析,所謂的靜態腳本解析就是把#{}解析成?靜態Sql解析是在解析Mapper.xml的時候執行的
publicRawSqlSource(Configurationconfiguration,Stringsql,ClassparameterType){
SqlSourceBuildersqlSourceParser=newSqlSourceBuilder(configuration);
Classclazz=parameterType==null?Object.class:parameterType;
//通過調用SqlSourceBuilder的parse方法來解析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);
}

}

下面我們來看下SqlSourceBuilder的parse方法

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

DynamicSqlSource

動態Sql解析主要由DynamicSqlSource來完成。這里面又是通過遞歸調進行sql解析。我們還是延用上面的Sql給大家講解。

publicclassDynamicSqlSourceimplementsSqlSource{

privatefinalConfigurationconfiguration;
privatefinalSqlNoderootSqlNode;

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

@Override
publicBoundSqlgetBoundSql(ObjectparameterObject){
//動態Sql解析上下文
DynamicContextcontext=newDynamicContext(configuration,parameterObject);
//rootSqlNode就是我們前面講解的,把動態Sql解析成SqlNode對象。外層為MixedSqlNode節點,節點存儲了
//節點下的所有子節點。里面遞歸調用并根據傳入參數的屬性檢查是否需要拼接sql
rootSqlNode.apply(context);
//這塊代碼和上面靜態Sql接代碼一致。
SqlSourceBuildersqlSourceParser=newSqlSourceBuilder(configuration);
ClassparameterType=parameterObject==null?Object.class:parameterObject.getClass();
//把我們動態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;
}

}

動態Sql解析apply方法博主只根據場景介紹下MixedSqlNode和IfSqlNode的apply方法。其他有興趣自己去研究下。邏輯大體一致,實現有些區別。

publicclassMixedSqlNodeimplementsSqlNode{
privatefinalListcontents;

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

//獲取循環SqlNode列表的所有SqlNode,調用apply方法根據傳入參數和條件進行靜態sql的拼接。
//列表中的SqlNode可能是一個簡單的SqlNode對象,也可能是一個MixedSqlNode或者有更多的嵌套。
//博主的例子就是3個嵌套If查詢。根據博主的Sql腳本,這里直接會調用IfSqlNode的apply方法。
//我們接下來看下IfSqlNode是如何實現的。
@Override
publicbooleanapply(DynamicContextcontext){
for(SqlNodesqlNode:contents){
sqlNode.apply(context);
}
returntrue;
}
}

IfSqlNode的apply

publicclassIfSqlNodeimplementsSqlNode{
//ExpressionEvaluator會調用ognl來對表達式進行解析
privatefinalExpressionEvaluatorevaluator;
privatefinalStringtest;
privatefinalSqlNodecontents;

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

@Override
publicbooleanapply(DynamicContextcontext){
//context.getBindings()里面就存儲這請求參數,這里是一個HashMap,OGNl里面代碼博主沒有研究。
//如果條件if成立,直接獲取contents中的SqlNode的apply方法進行動態腳本處理。
if(evaluator.evaluateBoolean(test,context.getBindings())){
contents.apply(context);
returntrue;
}
returnfalse;
}

}

這塊代碼很多遞歸調用,博主自認為講的不太透徹,所以大家看完務必自己去調試下。

總結

Mybatis動態Sql從解析到執行分為2個過程下面對這個2個過程進行簡單總結。
1.動態Sql生成SqlNode信息,這個過程發生在對select、update等Sql語句解析過程。如果是靜態Sql直接會把#{}替換成?。
2.動態Sql解析在獲取BoundSql時候觸發。會調用SqlNode的apply進行Sql解析成靜態Sql,然后把#{}替換成?,并綁定ParameterMapping映射。

審核編輯:彭靜
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SQL
    SQL
    +關注

    關注

    1

    文章

    762

    瀏覽量

    44117
  • 源碼
    +關注

    關注

    8

    文章

    639

    瀏覽量

    29185
  • 腳本
    +關注

    關注

    1

    文章

    389

    瀏覽量

    14858

原文標題:Mybatis動態Sql處理

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    在Delphi中動態地使用SQL查詢語句

    在Delphi中動態地使用SQL查詢語句在一般的數據庫管理系統中,通常都需要應用SQL查詢語句來提高程序的動態特性。下面介紹如何在Delph
    發表于 05-10 11:10

    DRDS分布式SQL引擎—執行計劃介紹

    摘要: 本文著重介紹 DRDS 執行計劃中各個操作符的含義,以便用戶通過查詢計劃了解 SQL 執行流程,從而有針對性的調優 SQL。DRDS分布式SQL引擎 — 執行計劃
    發表于 07-12 17:01

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

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

    為什么要動態sql語句?

    為什么要動態sql語句?因為動態sql語句能夠提供一些比較友好的機制1、可以使得一些在編譯過程中無法獲得完整的sql語句,在程序執行階段
    發表于 12-20 06:00

    基于數據窗口對象SQL 語法的動態移植技術探討

    在PowerBuilder9.0 應用程序中,動態創建特定顯示風格和結構比較復雜的數據窗口對象是開發人員所面臨的一大難題。文章就該問題提出通過移植數據窗口對象SQL 語法的方法來實現
    發表于 05-30 10:29 ?11次下載

    Delphi教程之在SQL查詢中使用動態參數

    Delphi教程之在SQL查詢中使用動態參數,學習Delphi的必備資料。
    發表于 03-31 11:29 ?4次下載

    SQL相關知識解析及SQL完全手冊的免費分享

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

    mybatis動態sql詳解

    本文詳細介紹了mybatis執行動態sql語句的方法。
    發表于 02-24 11:37 ?3833次閱讀

    SQL教程之什么是SQL能做什么SQL基礎的詳細資料介紹

    SQL 是一門 ANSI 的標準計算機語言,用來訪問和操作數據庫系統.SQL 語句用于取回和更新數據庫中的數據.SQL 可與數據庫程序協同工作,比如 MS Access、DB2、Informix、MS
    發表于 12-10 08:00 ?8次下載

    java的動態SQL詳細資料說明

    首先,所謂SQL動態和靜態,是指SQL語句在何時被編譯和執行,二者都是用在SQL嵌入式編程中的,這里所說的嵌入式是指將SQL語句嵌入在高級
    發表于 06-06 17:51 ?0次下載
    java的<b class='flag-5'>動態</b><b class='flag-5'>SQL</b>詳細資料說明

    SQL注入到Getshell的教程

    上一節,我們已經介紹了基本的SQL查詢語句,常見的SQL注入類型,DVWA靶場演示SQL注入。學習了上一節我們可以做到執行任意SQL語句,主
    的頭像 發表于 09-21 14:45 ?3022次閱讀

    一文掌握MyBatis的動態SQL使用與原理

    摘要:使用動態 SQL 并非一件易事,但借助可用于任何 SQL 映射語句中的強大的動態 SQL 語言,MyBatis 顯著地提升了這一特性的
    的頭像 發表于 01-06 11:27 ?983次閱讀

    PROC SQL介紹

    SQL(Structured Query Language)——結構化查詢語言,是用于檢索和更新數據的一種標準化語言,SQL在SAS中通過PROC SQL來實現。
    的頭像 發表于 05-19 16:10 ?2681次閱讀
    PROC <b class='flag-5'>SQL</b><b class='flag-5'>介紹</b>

    MyBatis動態sql是什么?MyBatis動態SQL最全教程

    動態 SQL 是 MyBatis 的強大特性之一。在 JDBC 或其它類似的框架中,開發人員通常需要手動拼接 SQL 語句。根據不同的條件拼接 SQL 語句是一件極其痛苦的工作。
    的頭像 發表于 08-10 10:18 ?953次閱讀

    oracle sql 定義變量并賦值

    在Oracle SQL中,變量是用來存儲數據值的標識符。通過定義和使用變量,我們可以在SQL語句中使用它們來存儲和處理數據,從而實現更靈活和動態的查詢和操作。 在Oracle SQL
    的頭像 發表于 12-06 10:46 ?2789次閱讀
    主站蜘蛛池模板: 亚洲欧洲日产国码中学| 魔乳 堕乳漫画acg产卵| 国产WW久久久久久久久久| 99久久综合精品免费| 最近高清中文字幕无吗免费看| 亚洲一区二区三区乱码在线欧洲| 无码成人AAAAA毛片含羞草| 色综合精品无码一区二区三区| 漂亮的av女演员| 飘雪在线观看免费完整版 | 亚洲狠狠网站色噜噜| 推倒美女总裁啪啪| 特级做A爰片毛片免费69| 桃花免费高清在线观看| 熟女人妻水多爽中文字幕| 少妇高潮久久久久7777| 特级毛片AAAAAA| 亚洲AV天堂无码麻豆电影| 亚洲mv在线观看| 亚洲色播永久网址大全| 亚洲午夜精品A片久久WWW软件 | 免费国产午夜理论不卡| 男人的天堂色偷偷| 女人被弄到高潮叫床免| 欧美日韩中文字幕综合图区| 青柠在线观看视频在线高清| 秋霞伦理电影在线看| 色mimi| 善良的小峓子2在钱免费中文字| 挺进绝色老师的紧窄小肉六| 新妺妺窝人体色WWW| 亚洲视频国产| 91嫩草国产在线观看免费| 9位美女厕所撒尿11分| 厨房玩朋友娇妻中文字幕| 国产精品久久久久久久AV下载| 国产亚洲tv在线观看| 久青草国产在视频在线观看| 欧美高清xxx| 为什么丈夫插我我却喜欢被打着插 | 97国产精品久久精品国产|