Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句_第1頁
Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句_第2頁
Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句_第3頁
Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句_第4頁
Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句@ApiModelProperty(value="是否啟用",example="0",position=2)

privateBooleanenabled;

*刪除標(biāo)示:0-未刪除,1-已刪除

@ApiModelProperty(value="刪除標(biāo)示",example="0",position=3)

privateBooleandeleted;

*當(dāng)前頁碼

@ApiModelProperty(value="當(dāng)前頁碼",example="1",position=4)

@Invisible

privatelongpi;

*當(dāng)前頁面大小

@ApiModelProperty(value="當(dāng)前頁面大小",example="10",position=5)

@Invisible

privatelongps;

}

最后需要對上述中的SimpleSelectLangDriver實現(xiàn)類中將被該注解聲明過的字段排除操作,代碼如下:

for(Fieldfield:parameterType.getDeclaredFields()){

//排除被Invisble修飾的變量

if(!field.isAnnotationPresent(Invisible.class)){

Stringtmp="iftest=\"_field!=null\"AND_column=#{_field}/if

sb.append(tmp.replaceAll("_field",field.getName()).replaceAll("_column",

CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,field.getName())));

}

如上所示,只是對SimpleSelectLangDriver類增加了if(!field.isAnnotationPresent(Invisible.class))這樣的判斷,已過濾多余的變量。

需要注意的是在使用Select的時候,傳入的參數(shù)前無需加入@Param注解,否則會導(dǎo)致Mybatis找不到參數(shù)而拋出異常,如需加入就需要綁定對象屬性(如在語句中就需要使用)。

2、自定義Selectin注解

在使用Mybatis注解的時候,發(fā)現(xiàn)其對SelectIn格式的查詢支持不是很友好,在字符串中輸入十分繁瑣,可以通過將自定義的標(biāo)簽轉(zhuǎn)成格式;下面便通過我們自己實現(xiàn)的LanguageDriver來實現(xiàn)SQL的動態(tài)解析:

DAO接口層中代碼如下:

@Select("SELECT*FROMadmin_roleWHEREidIN(#{roleIdList})")

@Lang(SimpleSelectInLangDriver.class)

ListRoleDOselectRolesByRoleId(ListIntegerroleIdList);

LanguageDriver實現(xiàn)類如下:

packagemon;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importorg.apache.ibatis.mapping.SqlSource;

importorg.apache.ibatis.scripting.LanguageDriver;

importorg.apache.ibatis.scripting.xmltags.XMLLanguageDriver;

importorg.apache.ibatis.session.Configuration;

*@authorAllen

*@date2025/3/9

*自定義Selectin注解,用于動態(tài)生成Selectin語句

publicclassSimpleSelectInLangDriverextendsXMLLanguageDriverimplementsLanguageDriver{

*Pattern靜態(tài)申明

privatefinalPatterninPattern=Ppile("\\(#\\{(\\w+)\\}\\)");

*實現(xiàn)自定義Selectin注解

*@paramconfiguration配置參數(shù)

*@paramscript入?yún)?/p>

*@paramparameterType參數(shù)類型

*@return轉(zhuǎn)換后的SqlSource

@Override

publicSqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,ClassparameterType){

Matchermatcher=inPattern.matcher(script);

if(matcher.find()){

script=matcher.replaceAll("foreachcollection=\"$1\"item=\"_item\"open=\"(\""

+"separator=\",\"close=\")\"#{_item}/foreach

script="script"+script+"/script

returnsuper.createSqlSource(configuration,script,parameterType);

}

通過自己實現(xiàn)LanguageDriver,在服務(wù)器啟動的時候,就會將我們自定義的標(biāo)簽解析為動態(tài)SQL語句,其等同于:

@Select("SELECT*"+

"FROMadmin_role"+

"WHEREidIN"+

"foreachitem='item'index='index'collection='list'open='('separator=','close=')'"+

"#{item}"+

"/foreach")

ListRoleDOselectRolesByRoleId(ListIntegerroleIdList);

通過實現(xiàn)LanguageDriver,剝離了冗長的動態(tài)拼接SQL語句,簡化了SelectIn的注解代碼。

需要注意的是在使用SelectIn的時候,則與上述相反需務(wù)必在傳入的參數(shù)前加@Param注解,否則會導(dǎo)致Mybatis找不到參數(shù)而拋出異常。

3、自定義Update的注解

在擴展update注解時,數(shù)據(jù)庫每張表的字段和實體類的字段必須遵循一個約定(數(shù)據(jù)庫中采用下劃線命名法,實體類中采用駝峰命名法)。

當(dāng)我們update的時候,會根據(jù)每個字段的映射關(guān)系,寫出如下代碼:

/**

*更新

*@paramroleDO角色信息

*@return影響行數(shù)

@Update("updateadmin_rolesetrole_name=#{roleDO.roleName},"

+"enabled=#{roleDO.enabled},deleted=#{roleDO.deleted},modifierId=#{roleDO.modifierId},"

+"modifier=#{roleDO.modifier},last_modified=#{roleDO.lastModified}whereid=#{roleDO.id}")

intupdate(@Param(value="roleDO")RoleDOroleDO);

上述的代碼我們可以將實體類中的駝峰式代碼轉(zhuǎn)換為下劃線式命名方式,這樣就可以將這種映射規(guī)律自動化,但此代碼存在一定的問題,就是當(dāng)你在更新部分字段時其余所有字段原來的值必須傳入,否則可能會將原有數(shù)據(jù)更新為null或空,亦或在更新時先查詢原數(shù)據(jù)后將變更的數(shù)據(jù)進行操作,這樣不僅增加了數(shù)據(jù)庫查詢操作且會造成代碼冗余,而經(jīng)過實現(xiàn)LanguageDriver后,注解代碼如下:

/**

*更新

*@paramroleParam角色信息

@Update("updateadmin_role(#{roleDO})whereid=#{id}")

@Lang(SimpleUpdateLangDriver.class)

voidupdate(RoleParamroleParam);

相對于原始的代碼量有很大的減少,尤其是對于一個類中字段越多,改善也就越明顯。實現(xiàn)方式為:

packagemon;

importjava.lang.reflect.Field;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importorg.apache.ibatis.mapping.SqlSource;

importorg.apache.ibatis.scripting.LanguageDriver;

importorg.apache.ibatis.scripting.xmltags.XMLLanguageDriver;

importorg.apache.ibatis.session.Configuration;

importmon.base.CaseFormat;

*@authorAllen

*@date2025/3/9

*自定義Update注解,用于動態(tài)生成Update語句

publicclassSimpleUpdateLangDriverextendsXMLLanguageDriverimplementsLanguageDriver{

*Pattern靜態(tài)申明

privatefinalPatterninPattern=Ppile("\\(#\\{(\\w+)\\}\\)");

*實現(xiàn)自定義Update注解

*@paramconfiguration配置參數(shù)

*@paramscript入?yún)?/p>

*@paramparameterType參數(shù)類型

*@return轉(zhuǎn)換后的SqlSource

@Override

publicSqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,ClassparameterType){

Matchermatcher=inPattern.matcher(script);

if(matcher.find()){

StringBuildersb=newStringBuilder();

sb.append("set

for(Fieldfield:parameterType.getDeclaredFields()){

//排除被Invisble修飾的變量

if(!field.isAnnotationPresent(Invisible.class)){

Stringtmp="iftest=\"_field!=null\"_column=#{_field},/if

sb.append(tmp.replaceAll("_field",field.getName()).replaceAll("_column",

CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,field.getName())));

sb.deleteCharAt(sb.lastIndexOf(","));

sb.append("/set

script=matcher.replaceAll(sb.toString());

script="script"+script+"/script

returnsuper.createSqlSource(configuration,script,parameterType);

}

注意此處在傳入的參數(shù)前無需加入@Param注解。

4、自定義Insert的注解同理

我們可以抽象化Insert操作,簡化后的Insert注解為:

/**

*插入

*@paramroleParam角色信息

@Insert("insertintoadmin_role(#{roleDO})")

@Lang(SimpleInsertLangDriver.class)

voidinsert(RoleParamroleParam);

SimpleInsertLanguageDriver實現(xiàn)類代碼如下:

packagemon;

importjava.lang.reflect.Field;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importorg.apache.ibatis.mapping.SqlSource;

importorg.apache.ibatis.scripting.LanguageDriver;

importorg.apache.ibatis.scripting.xmltags.XMLLanguageDriver;

importorg.apache.ibatis.session.Configuration;

importmon.base.CaseFormat;

*@authorAllen

*@date2025/3/9

*自定義Insert注解,用于動態(tài)生成Insert語句

publicclassSimpleInsertLangDriverextendsXMLLanguageDriverimplementsLanguageDriver{

*Pattern靜態(tài)申明

privatefinalPatterninPattern=Ppile("\\(#\\{(\\w+)\\}\\)");

*實現(xiàn)自定義Insert注解

*@paramconfiguration配置參數(shù)

*@paramscript入?yún)?/p>

*@paramparameterType參數(shù)類型

*@return轉(zhuǎn)換后的SqlSource

@Override

publicSqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,ClassparameterType){

Matchermatcher=inPattern.matcher(script);

if(matcher.find()){

StringBuildersb=newStringBuilder();

StringBuildertmp=newStringBuilder();

sb.append("(");

for(Fieldfield:parameterType.getDeclaredFields()){

if(!field.isAnnotationPresent(Invisible.class)){

sb.append(

CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,field.getName())

+",");

tmp.append("#{"+field.getName()+"},");

sb.deleteCharAt(sb.lastIndexOf(","));

tmp.deleteCharAt(tmp.lastIndexOf(","));

sb.append(")values("

+tmp.toString()+")");

script=matcher.replaceAll(sb.toString());

script="script"+script+"/script

returnsuper.createSqlSource(configuration,script,parameterType);

}

至此我們完成了基本的@Select、@Update、@Insert自定義注解,簡單化繁雜的拼接SQL語句的尷尬,但以上代碼在SimpleSelectLangDriver中還有一定的局限性,比如對于一些字段我們需要使用like來進行查詢,這時就需要對上述自定義Seleect注解進行完善以實現(xiàn)各種業(yè)務(wù)的場景。

四、注意事項遇到的一些坑

務(wù)必確保數(shù)據(jù)庫中列名和實體類中字段能一一對應(yīng)。在使用自定義SQL解析器的時候,只能傳入一個參數(shù),即相應(yīng)的對象參數(shù)即可;傳入多個參數(shù)會導(dǎo)致解析器中獲得到的class對象改變,使得sql解析異常。Update的實現(xiàn)能滿足大部分的業(yè)務(wù),但有些業(yè)務(wù)場景可以會遇到根據(jù)查詢條件來更新查詢參數(shù)的情況,比如UpdateuserSETuesr_name=王雷WHEREuser_name=小王在這樣的場景中請不要使用自定義的SQL解析器。請使用Mybatis3.3以上版本。3.2以下版本會存在一些Bug,在本例中使用的為mybatis-spring-boot-starter1.3.1,其Mybatis為3.4.5。

五、總結(jié)

通過實現(xiàn)LanguageDriver,我們可以很方便的自定義自己的注解。在遵循一些約定的情況下(數(shù)據(jù)庫下劃線命名,實體駝峰命名),我們可以大幅度的減少SQL的編寫量,并且可以完全的屏蔽掉麻煩的XML編寫方式,再也不用再編寫復(fù)雜的拼接動態(tài)SQL的煩惱,簡化工作,提高開發(fā)效率。

//

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論