版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年寧夏體育職業(yè)學(xué)院單招綜合素質(zhì)考試模擬試題含詳細答案解析
- 2026年1月黑龍江大慶市肇州縣招聘公益性崗位人員35人考試重點試題及答案解析
- 2026年天津仁愛學(xué)院高職單招職業(yè)適應(yīng)性測試模擬試題及答案詳細解析
- 2026貴州六盤水六枝特區(qū)面向社會公開招聘事業(yè)單位工作人員35人考試重點題庫及答案解析
- 2026年景德鎮(zhèn)陶瓷職業(yè)技術(shù)學(xué)院單招職業(yè)技能考試備考試題含詳細答案解析
- 2026年西安市未央?yún)^(qū)漢城社區(qū)衛(wèi)生服務(wù)中心招聘(12人)考試重點題庫及答案解析
- 2026湖南長沙市芙蓉區(qū)教育局屬學(xué)校公開招聘小學(xué)編外合同制教師33人參考考試題庫及答案解析
- 2026年貴州經(jīng)貿(mào)職業(yè)技術(shù)學(xué)院單招職業(yè)技能考試備考題庫含詳細答案解析
- 2026年麗江市招聘事業(yè)單位工作人員(610人)參考考試試題及答案解析
- 2026年九江理工職業(yè)學(xué)院單招職業(yè)技能考試備考題庫含詳細答案解析
- 空氣栓塞課件教學(xué)
- 2025年國家市場監(jiān)管總局公開遴選公務(wù)員面試題及答案
- 肌骨康復(fù)腰椎課件
- 2026年山東城市服務(wù)職業(yè)學(xué)院單招職業(yè)適應(yīng)性考試題庫附答案詳解
- 患者身份識別管理標(biāo)準(zhǔn)
- 2025年10月自考04184線性代數(shù)經(jīng)管類試題及答案含評分參考
- 2025年勞動保障協(xié)理員三級技能試題及答案
- 20以內(nèi)加減法混合口算練習(xí)題1000道(附答案)
- 全國高考體育單招考試政治模擬試卷試題及答案2025年
- 產(chǎn)品質(zhì)量檢查報告表專業(yè)標(biāo)準(zhǔn)模板版
- 2025年及未來5年中國心血管病醫(yī)院行業(yè)競爭格局及投資戰(zhàn)略研究報告
評論
0/150
提交評論