MyBatis 動態(tài) SQL 優(yōu)化之標簽的實戰(zhàn)與技巧(常見用法)
動態(tài)SQL詳解
動態(tài)SQL是一種在運行時生成和執(zhí)行SQL語句的技術(shù),廣泛應(yīng)用于處理復(fù)雜查詢條件和動態(tài)數(shù)據(jù)需求。以下是動態(tài)SQL的核心概念、常見用法及注意事項。
一、動態(tài)SQL的核心概念
1.1 什么是動態(tài)SQL?
動態(tài)SQL是一種靈活的SQL編寫方式,允許開發(fā)者在程序運行時根據(jù)條件生成SQL語句,而不是在編譯時固化。動態(tài) SQL 是Mybatis的強大特性之一,能夠完成不同條件下不同的 SQL拼接。
1.2 動態(tài)SQL的優(yōu)點
- 靈活性:根據(jù)不同條件生成不同的SQL語句。
- 復(fù)用性:減少重復(fù)代碼,提高代碼維護性。
- 性能:在某些場景下可以優(yōu)化查詢性能。
1.3 動態(tài)SQL的常見用途
- 處理多條件查詢。
- 動態(tài)指定表名、字段或排序方式。
- 處理批量操作。
二、動態(tài)SQL的常見用法(XML方式)
數(shù)據(jù)庫數(shù)據(jù)信息
2.1 < if > 標簽
主要用于在動態(tài)SQL中根據(jù)條件判斷是否執(zhí)行某個SQL片段。它可以根據(jù)傳入的參數(shù)或條件動態(tài)地添加或移除SQL語句的一部分,從而實現(xiàn)靈活的查詢需求。
UserInfoMapperXML.java 接口代碼
Integer insertUserBySQL(UserInfo userInfo);
UserInfoMapper.xml 文件
<insert id="insertUserBySQL"> insert into user_info ( username, password, age, <if test="gender!=null"> gender, </if> phone) values( #{username}, #{password}, #{age}, <if test="gender!=null"> #{gender}, </if> #{phone}) </insert>
測試類沒有插入gender的情況
:
@Test void insertUserBySQL() { UserInfo userInfo=new UserInfo(); userInfo.setUsername("qq"); userInfo.setPassword("qq"); userInfo.setAge(46); userInfo.setPhone("465131"); userInfoMapperXML.insertUserBySQL(userInfo); }
運行結(jié)果:
可以看到把gender
這個字段使用if標簽之后,這個字段就被移除了。
2.2< trim>標簽
trim標簽在動態(tài)SQL中起到格式化SQL語句的作用,允許開發(fā)者在生成SQL時自動處理空格、換行符以及前綴后綴的添加。通過合理使用trim標簽,可以簡化動態(tài)SQL的開發(fā),提高代碼的可讀性和維護性,同時確保生成的SQL語句高效且正確。
prefix
:表示整個語句塊,以prefix的值作為前綴suffix
:表示整個語句塊,以suffix的值作為后綴prefixOverrides
:表示整個語句塊要去除掉的前綴suffixOverrides
:表示整個語句塊要去除掉的后綴
為了更好的了解trim標簽的作用,先來個錯誤的示范。
XML.java
文件
Integer insertUserBySQL1(UserInfo userInfo);
.xml
文件
<insert id="insertUserBySQL1"> insert into user_info <trim prefix="(" suffix=")" > <if test="username!=null"> username, </if> <if test="password!=null"> password, </if> <if test="age!=null"> age, </if> <if test="gender!=null"> gender, </if> <if test="phone!=null"> phone </if> </trim> values <trim suffix="(" prefix=")" > <if test="username!=null"> #{username}, </if> <if test="password!=null"> #{password}, </if> <if test="age!=null"> #{age}, </if> <if test="gender!=null"> #{gender}, </if> <if test="phone"> #{phone} </if> </trim> </insert>
測試類
@Test void insertUserBySQL1() { UserInfo userInfo=new UserInfo(); userInfo.setUsername("zhangs"); userInfo.setPassword("123461"); userInfo.setPhone("7489"); userInfoMapperXML.insertUserBySQL1(userInfo);
運行結(jié)果:
修改 .xml
文件,通過trim標簽給SQL語句添加或者去除前后綴。
再進行測試;
可以看到成功了。
2.3 <where>標簽
標簽用于在動態(tài)SQL中自動處理WHERE子句的生成,簡化多條件查詢的開發(fā)。它能自動處理邏輯連接詞(如AND、OR)以及去除多余的關(guān)鍵字,使得代碼更加簡潔和高效。
XML.java
文件代碼:
List<UserInfo> selectByWhere();
.xml
文件代碼
<select id="selectByWhere" resultType="com.sliqvers.model.UserInfo"> select * from user_info <where> <if test="username!=null"> and username=#{username} </if> <if test="password!=null"> or password=#{password} </if> <if test="age!=null"> and age=#{age} </if> <if test="phone!=null"> or phone=#{phone} </if> </where> </select>
測試類
@Test void selectByWhere() { userInfoMapperXML.selectByWhere().stream().forEach(x-> System.out.println(x)); }
生成的SQL:
當(dāng)username和phonel都有值:SELECT * FROM user_info WHERE username = ? AND phone =?;
當(dāng)只有username有值:SELECT * FROM user_info WHERE username =?;
當(dāng)兩者都為null:SELECT * FROM user_info;
2.4<set>標簽
標簽在UPDATE語句中起到動態(tài)設(shè)置字段值的作用,自動處理SET關(guān)鍵字和逗號,避免空更新。通過合理使用
<set>
標簽,可以簡化代碼,提高SQL執(zhí)行效率,確保系統(tǒng)的安全性和穩(wěn)定性。
XML.java
文件
Integer upadteUserSql(UserInfo userInfo);
.xml
文件
<update id="upadteUserSql"> update user_info <set> <if test="password!=null"> password = #{password} , </if> <if test="username!=null"> username = #{username}, </if> </set> where id=#{id} </update>
測試類:
@Test void upadteUserSql() { UserInfo userInfo=new UserInfo(); userInfo.setUsername("Sliqvers"); userInfo.setPassword("111111"); userInfo.setId(1); userInfoMapperXML.upadteUserSql(userInfo); }
運行結(jié)果:
生成的SQL:
當(dāng)username和password都有值:UPDATE user_info SET username = ?, email = ? WHERE id = ?
當(dāng)只有username有值:UPDATE user_info SET username = ? WHERE id = ?
當(dāng)只有password有值:UPDATE users_info SET password = ? WHERE id = ?
當(dāng)兩者都為null:UPDATE user_info WHERE id = ?
2.5 <foreach> 標簽
<foreach>
標簽在動態(tài)SQL中起到遍歷集合或數(shù)組的作用,生成IN子句、批量INSERT或UPDATE等操作。通過合理使用標簽,可以簡化批量操作的SQL拼接,提高開發(fā)效率和系統(tǒng)性能。同時,注意避免SQL注入和空集合處理等問題,可確保動態(tài)SQL的安全性和可靠性。
<foreach>
標簽的屬性
collection:必填,指定要遍歷的集合名。
item:必填,指定遍歷時的變量名。
open:可選,遍歷開始時添加的字符串。
close:可選,遍歷結(jié)束時添加的字符串。
separator:可選,遍歷時的分隔符(默認",")。
index:可選,遍歷時的索引變量。
select:可選,用于嵌套查詢。
XML.java
接口
List<UserInfo> selectBySql(List<Integer> ids);
.xml
文件
<select id="selectBySql" resultType="com.sliqvers.model.UserInfo"> select * from user_info where id in <foreach collection="ids" open="(" close=")" separator="," item="id"> #{id} </foreach> </select>
測試類
@Test void selectBySql() { List<Integer> ids=new ArrayList<>(); ids.add(1); ids.add(2); ids.add(3); userInfoMapperXML.selectBySql(ids).stream().forEach(x-> System.out.println(x)); }
運行結(jié)果:
生成的SQL:
ids = [1, 2, 3] 時:SELECT * FROM user_info WHERE id IN (1, 2, 3)
2.6 <include>標簽
在xml映射?件中配置的SQL,有時可能會存在很多重復(fù)的片段,此時就會存在很多冗余的代碼,我們可以對重復(fù)的代碼片段進行抽取,將其通過
<sql>
標簽封裝到?個SQL片段,然后再通過<include>
標簽進行引用。
定義一個常用的WHERE條件
<sql id="allColumn"> id, username, age, gender, phone, delete_flag, create_time, update_time </sql>
通過
<include>
標簽在原來抽取的地方進行引用。操作如下:
<select id="queryAllUser" resultMap="BaseMap"> select <include refid="allColumn"></include> from user_info </select>
三、動態(tài)SQL的注意事項
3.1 SQL注入問題(搞破壞)
- 風(fēng)險:直接拼接用戶輸入可能導(dǎo)致SQL注入。
- 解決方案:使用參數(shù)化查詢或ORM框架(如MyBatis)提供的安全功能。
3.2 performance
- 執(zhí)行計劃緩存:動態(tài)SQL可能導(dǎo)致數(shù)據(jù)庫無法有效利用執(zhí)行計劃緩存。
- 優(yōu)化建議:盡量減少動態(tài)SQL的使用場景,或者使用有限的條件組合。
3.3 動態(tài)SQL的可讀性和維護性
- 復(fù)雜性:動態(tài)SQL可能使代碼更難閱讀和維護。
- 建議:合理分層代碼,遵循編碼規(guī)范。
四、總結(jié)
本文通過詳細的示例和實際應(yīng)用場景,介紹了如何有效利用這些標簽來優(yōu)化 MyBatis 配置,提升開發(fā)效率,確保 SQL 的高效執(zhí)行和安全性。學(xué)習(xí)這些技巧,幫助開發(fā)者更高效地構(gòu)建和維護數(shù)據(jù)庫交互層。
到此這篇關(guān)于MyBatis 動態(tài) SQL 優(yōu)化:標簽的實戰(zhàn)與技巧的文章就介紹到這了,更多相關(guān)MyBatis 動態(tài) SQL 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis中實現(xiàn)動態(tài)SQL標簽
- MyBatis的@SelectProvider注解構(gòu)建動態(tài)SQL方式
- Mybatis之動態(tài)SQL使用小結(jié)(全網(wǎng)最新)
- Mybatis動態(tài)Sql標簽使用小結(jié)
- MyBatis中的XML實現(xiàn)和動態(tài)SQL實現(xiàn)示例詳解
- MyBatis 動態(tài)SQL之where標簽的使用
- Mybatis的@select和@SelectProvider注解方式動態(tài)SQL語句解讀
- Mybatis使用XML實現(xiàn)動態(tài)sql的示例代碼
- Mybatis使用注解實現(xiàn)復(fù)雜動態(tài)SQL的方法詳解
相關(guān)文章
淺談SpringBoot 中關(guān)于自定義異常處理的套路
這篇文章主要介紹了淺談SpringBoot 中關(guān)于自定義異常處理的套路,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Kotlin中l(wèi)et、run、with、apply及also的用法和差別
作用域函數(shù)是Kotlin比較重要的一個特性,分為5種let、run、with、apply及also,這五個函數(shù)的工作方式非常相似,但是我們需要了解這5種函數(shù)的差異,以便在不同的場景更好的利用它,這篇文章主要介紹了Kotlin中l(wèi)et、run、with、apply及also的差別,需要的朋友可以參考下2023-11-11SpringSecurity JWT基于令牌的無狀態(tài)認證實現(xiàn)
Spring Security中實現(xiàn)基于JWT的無狀態(tài)認證是一種常見的做法,本文就來介紹一下SpringSecurity JWT基于令牌的無狀態(tài)認證實現(xiàn),感興趣的可以了解一下2025-04-04java.lang.FileNotFoundException 異常的正確解決方法(親測有效)
java.io.FileNotFoundException是一個在文件操作過程中常見的異常,它屬于IOException的一個子類,這篇文章主要介紹了java.lang.FileNotFoundException 異常的正確解決方法(親測有效),需要的朋友可以參考下2024-01-01解決Eclipse/STS中出現(xiàn)Resource is out of sync with the file system
今天小編就為大家分享一篇關(guān)于解決Eclipse/STS中出現(xiàn)Resource is out of sync with the file system的異常問題,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12Springboot項目因為kackson版本問題啟動報錯解決方案
這篇文章主要介紹了Springboot項目因為kackson版本問題啟動報錯解決方案,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07