Mybatis多表查詢與動態(tài)SQL特性詳解
1.較復雜的查詢操作
1.1 參數(shù)占位符 #{} 和 ${}
#{}
:預處理符,如將id=#{2}
替換為id=?
,然后使用2
替換?
。
${}
:替換符,如將id=${2}
替換為id=2
。
兩種占位符都可以正常使用的場合:傳入的參數(shù)類型是數(shù)值類型
使用${}
:
select * from userinfo where id=${id} select * from userinfo where id=2
使用#{}
:
select * from userinfo where id=#{id} select * from userinfo where id=?
對于這兩種參數(shù)占位符,個人建議能使用#{}
就使用#{}
,因為${}
存在SQL注入的問題,以及如果傳入的類型是字符串也會出類型。
只能使用#{}
而不能使用${}
的場合:傳入參數(shù)類型為String
使用${}
:
select * from userinfo where username=${username} //實際執(zhí)行的語句 Preparing: select * from userinfo where username=張三
但是在sql中通過字符串來查詢數(shù)據(jù),是需要加上引號的,而使用${}
生成的sql并沒有帶引號,因此不適用于字符串參數(shù)的sql。
使用#{}
:
select * from userinfo where username=#{username} //實際執(zhí)行語句 select * from userinfo where username=?
由于使用#{}
是將目標參數(shù)替換為占位符,然后利用JDBC中的占位符機制實現(xiàn)sql語句的填充,所以使用#{}
構造的sql是可以正常運行的,并且沒有SQL注入的問題。
所以,#{}
相比于${}
,它支持所有類型的參數(shù),包括數(shù)值類與字符串類,而${}
支持數(shù)值類型,不支持字符串類型的參數(shù),但也可以在原來sql里面為${}
外面加上一對引號。
select * from userinfo where username='${username}' //實際執(zhí)行語句 Preparing: select * from userinfo where username='張三'
當傳遞的參數(shù)為字符串類型的時候,雖然加上一對引號,使用${}
也可以做到,但是${}
存在SQL注入問題,所以仍然不推薦,有關SQL注入后面我們會介紹到。
大部分場合下,使用#{}
都可以解決,但還是存在一小部分只能是${}
來處理的。
如當我們需要按照升序或者逆序得到數(shù)據(jù)庫查詢結果的時候,這種場合就只能使用${}
,使用#{}
會報錯,我們來演示一下。
首先,我們在Mapper
接口中聲明一個方法:作用就是按照排序獲取結果集
public List<UserInfo> getOrderList(@Param(value = "order") String order);
我們再去xml
文件中去寫sql語句:首先我們使用$
進行演示
<select id="getOrderList" resultType="com.example.demo.model.UserInfo"> select * from userinfo order by createtime ${order}; </select>
我們進行一個單元測試,單元測試代碼很簡單,就是調用sql,然后得到結果集:
@Test void getOrderList() { List<UserInfo> userMappers = userMapper.getOrderList("desc"); System.out.println(userMappers); }
單元測試結果:
可以正常查詢,得到的結果與預期也是相同的。
我們再來試一試使用#{}
來構造sql語句:
<select id="getOrderList" resultType="com.example.demo.model.UserInfo"> select * from userinfo order by createtime #{order}; </select>
單元測試邏輯與代碼不變,我們再來看看單元測試執(zhí)行的一個結果:
我們發(fā)現(xiàn)程序報錯了,這是因為使用了desc
的字符串替換了占位符,而我們所需要的不是一個desc
字符串,而是直接一個desc
的關鍵字,所以sql也拋出了語法錯誤,最終執(zhí)行的sql為:
select * from userinfo order by createtime ‘desc';
期望執(zhí)行的sql為:
select * from userinfo order by createtime desc;
所以在傳遞sql關鍵字的時候,不能使用#{}
,只能使用${}
。
1.2SQL注入
SQL注入就是使用${}
,使用一些特殊的語句,來達到非法獲取數(shù)據(jù)的目的,如不通過正確的密碼獲取某賬戶的信息,下面我們來演示一下,就以登錄的例子來演示,SQL注入可以在不知道密碼的前提下登錄成功,并且獲取到用戶的相關信息。
首先我將數(shù)據(jù)庫只保留一個用戶信息,目的是為了方便演示SQL注入問題:
第一步,在Mapper
接口中定義方法login
,返回登錄成功的用戶對象。
public UserInfo login(@Param("username") String username, @Param(("password")) String password);
第二步,在xml
文件中編寫SQL語句,我們需要演示SQL注入,所以我們使用${}
來構造sql語句。
<select id="login" resultType="com.example.demo.model.UserInfo"> select * from userinfo where username='${username}' and password='${password}'; </select>
第三步,編寫測試類,我們在這個測試類中,傳入有注入問題的SQL語句' or 1='1
,使得不需要密碼就能拿到相關的用戶信息。
@Test void login() { String username = "admin"; String password = "' or 1='1"; UserInfo userInfo = userMapper.login(username, password); System.out.println(userInfo); }
單元測試運行結果:
我們在不知道用戶密碼的情況下,登錄成功,并拿到了用戶的信息。
最終執(zhí)行的一段sql語句為:
select * from userinfo where username='admin' and password='' or 1='1';
相當于它在原來條件判斷的語句下,后面有加上一個或的邏輯,并且或后面的表達式為true
,這樣就使得原來的SQL語句中的條件判斷部分一定為真,所以就在密碼不知道的情況下拿到了用戶的基本信息。
所以我們能不使用#{}
就不使用${}
,因為存在SQL注入問題,如果必須使用${}
則需要驗證一下傳遞的參數(shù)是否合法,比如上面定義排序的sql,傳遞的參數(shù)只能是desc
或者是asc
,如果不是就不能執(zhí)行這條SQL,防止SQL注入的發(fā)生。
1.3like查詢
在Mybatis中使用like
查詢比較特殊,因為直接使用#{}
會報錯,而使用${}
,由于輸入的字符串情況很多,無法做到枚舉,驗證比較困難,無法避免SQL注入問題。
首先,我們來演示使用#{}
進行like
查詢,步驟我就不詳細寫了,就是查詢的步驟。
第一步,聲明方法。
public List<UserInfo> getListByName(@Param("username") String username);
第二步,xml寫sql。
<select id="getListByName" resultType="com.example.demo.model.UserInfo"> select * from userinfo where username like '%#{username}%' </select>
第三步,單元測試。
@Test void getListByName() { String username = "a"; List<UserInfo> list = userMapper.getListByName(username); for (UserInfo userInfo : list) { System.out.println(userInfo); } }
運行結果:報錯了,因為#{}
會被替換成一個字符串,而在這個%#{username}%
語句中#{username}
不能帶上引號,帶上就違背SQL語法,造成錯誤。
這個時候,由于#{}
多出一對引號,${}
無法枚舉所有情況進行驗證會產生SQL注入,所以不能直接使用#{}
,我們需要搭配MySQL內置的字符串拼接語句concat
。
我們將sql改為concat
進行字符串拼接:
<select id="getListByName" resultType="com.example.demo.model.UserInfo"> select * from userinfo where username like concat('%', #{username}, '%') </select>
重新測試一下,發(fā)現(xiàn)可以正常執(zhí)行了:
1.4resultType與resultMap
resultType表示數(shù)據(jù)庫返回的數(shù)據(jù)映射在java程序中所對應的類型,只要定義類中的字段名與數(shù)據(jù)庫中表的字段名字一致就沒有任何問題,但是如果字段名存在沖突,則沖突的字段無法獲取到數(shù)據(jù)庫查詢的結果。
比如用戶名屬性在數(shù)據(jù)庫中的名字是username
,而在java程序類中的屬性名為name
,此時通過mybatis將數(shù)據(jù)傳遞到程序中的對象時,獲取到的name
屬性為null
,就不能正確地獲取到對應的屬性值,為了解決這個數(shù)據(jù)庫字段與類中中字段不匹配的問題,我們需要使用到resultMap。
resultMap的使用方式就是在xml
文件中設置<resultMap>
標簽,至少需要設置兩個屬性,一個是id
表示你這個resultMap標簽的名字,還有一個是type
屬性,它表示映射到程序中類的類型,需包含包名。
這個標簽里面需要設置至少兩個子標簽,一個是id
標簽,另外一個是result
標簽,前者表示主鍵,后者表示數(shù)據(jù)庫表中普通的列,這兩種標簽也是至少需要設置兩個屬性,一個是column
表示數(shù)據(jù)庫表中的字段名,另外一個是property
表示程序類中的字段名,如果只是在單表進行查詢,只設置不同字段名的映射就可以了,但是如果是多表查詢,必須將數(shù)據(jù)表中所有的字段與類中所有的字段生成映射關系。
就像下面這樣,圖中類與數(shù)據(jù)表字段是相同的,實際情況會存在不同的字段名:
1.4多表查詢
1.4.1一對一表映射
一對一關系就是對于一個屬性只與另外一個屬性有關系的映射,這就是一對一的關系,舉個例子,對于一篇博客,它只會對應到一個用戶,則博客與用戶的關系是一對一的關系,下面我們嘗試在mybatis中實現(xiàn)一對一多表聯(lián)查。
那么,首先我們先將數(shù)據(jù)庫的博客表與查程序中的博客類對應起來,就是按照數(shù)據(jù)庫中的博客表建立一個類:
@Data public class Articleinfo { private Integer id; private String title; private String content; private String createtime; private String updatetime; private Integer uid; private Integer rcount; private Integer state; //不妨多一個屬性,用戶表 private UserInfo userInfo; }
目前文章表中只有一條數(shù)據(jù),如下圖:
第二步,創(chuàng)建Mapper
接口和對應的xml
文件。
第三步,在接口中聲明方法和在xml中寫sql標簽與語句。
//根據(jù)文章名稱獲取文章對象 public Articleinfo getArticleById(@Param("id") Integer id);
<select id="getArticleById" resultType="com.example.demo.model.Articleinfo"> select * from articleinfo where id=#{id}; </select>
第四步,編寫測試方法,我們直接調用查詢方法,然后使用日志輸出對象。
@Test void getArticleById() { Articleinfo articleinfo = articleMapper.getArticleById(1); log.info("文章詳情:" + articleinfo); }
由于我們數(shù)據(jù)表與類的字段名是一致的,那些普通的屬性都一一對應上了,都成功被賦值了,但是由于UserInfo
類在數(shù)據(jù)表中沒有,所以并沒有得到UserInfo對象,如果我們想要拿到這個對象,我們得使用resultMap
。
問題主要有兩個,第一,數(shù)據(jù)庫查詢到的用戶表沒有映射到UserInfo
對象,第二,查詢的SQL語句是單表查詢語句,不是多表查詢語句。
所以想要實現(xiàn)一對一多表查詢,需要設置多表查詢SQL語句,我們使用左外連接進行多表查詢:
<select id="getArticleById" resultMap="BaseMap"> select a.*, u.* from articleinfo as a left join userinfo as u on a.uid=u.id where a.id=#{id}; </select>
此外,我們除了設置UserInfo
與Articleinfo
類中每個屬性與數(shù)據(jù)表的映射之外,我們還要在Articleinfo
類對應的resultMap
中使用association
標簽。最少需要設置兩個屬性,一個是property
表示在主表Articleinfo
中對應副表UserInfo
映射對象的變量名,另外一個是副表UserInfo
對應的resultMap
。
Articleinfo
類對應的resultMap:
<resultMap id="BaseMap" type="com.example.demo.model.Articleinfo"> <id column="id" property="id"></id> <result column="title" property="title"></result> <result column="content" property="content"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="uid" property="uid"></result> <result column="rcount" property="rcount"></result> <result column="state" property="state"></result> <association property="userInfo" resultMap="com.example.demo.mapper.UserMapper.BaseMap"></association> </resultMap>
UserInfo
類對應的resultMap:
<resultMap id="BaseMap" type="com.example.demo.model.UserInfo"> <!-- column 表示數(shù)據(jù)庫字段名 property 表示對應對象的字段名,設置這兩個值可以建立映射--> <!-- 主鍵約束--> <id column="id" property="id"></id> <!--普通變量映射--> <result column="username" property="username"></result> <result column="password" property="password"></result> <result column="photo" property="photo"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="state" property="state"></result> </resultMap>
如果UserInfo
類的resultMap沒有將所有的屬性都與數(shù)據(jù)庫的表映射,就會造成獲取到的userInfo
對象中的數(shù)據(jù)不完整,假設只設置了id
與name
的映射,那獲取到的對象只有id
與name
有值。
將兩張表的resultMap映射好后,我們運行同樣的單元測試案例,運行結果如下:
但是,仍然存在一個問題,那就是我們所建的兩個表存在名字相同的字段,可能會出現(xiàn)數(shù)據(jù)覆蓋的情況,如兩個表的主鍵都叫id
,但是id
在兩個表的含義是不同的,在用戶表它表示用戶id
,在文章表它表示文章的id
,現(xiàn)在我們將獲取兩表的數(shù)據(jù)的id
改為不相同,再來看一看單元測試運行的結果:
按理來說,由于不存在id
為1
的用戶,所以獲取到UserInfo
對象應該為null
才對,但是運行的結果卻存在UserInfo
對象,并且與文章表的重名字段都被賦值了文章表中的數(shù)據(jù),為了解決這個問題,我們必須在文章表(主表)的resultMap
中設置屬性columnPrefix
,它的值隨便設置,作用是識別副表字段時加上一段前綴,如我們給用戶表的字段加上前綴u_
,此時sql中就不能使用*
來一次表示所有元素了,需要一個一個單獨設置,并將字段全部重命名,帶上u_
前綴 。
association
字段設置:
<association property="userInfo" columnPrefix="u_" resultMap="com.example.demo.mapper.UserMapper.BaseMap" ></association>
SQL語句需要將用戶表的字段全部重命名:
<select id="getArticleById" resultMap="BaseMap"> select a.*, u.id as u_id, u.username as u_username, u.password as u_password, u.photo as u_photo, u.createtime as u_createtime, u.updatetime as u_updatetime, u.state as u_state from articleinfo as a left join userinfo as u on a.uid=u.id where a.id=#{id}; </select>
我們將userInfo
對應的用戶表的id
再改回為1
,讓查詢有關于UserInfo
類的數(shù)據(jù)。
再次運行單元測試案例:
我們是能夠獲取到相應的數(shù)據(jù)的,所以如果兩個表字段重名了,進行多表查詢時,需要設置columnPrefix
屬性,這樣才能夠避免不同表同名字段數(shù)據(jù)覆蓋的問題。
所以,在創(chuàng)建數(shù)據(jù)庫的數(shù)據(jù)表時,盡量不要讓表與表中的字段重名。
1.4.2一對多表映射
一對多的關系,就是對于一個屬性,它對映著多個其他的屬性,比如用戶與博客之間的關系,一個用戶可以對應多篇博客,則用戶與博客之間的關系就是一對多的關系。同樣的下面我們嘗試使用mybatis實現(xiàn)多對多的多表聯(lián)查。
下面我們以用戶表為主,文章表為輔,來演示如何進行一對多關系的多表查詢。
既然是一對多的關系,那我們可以在UserInfo
類中加上一個儲存ArticleInfo
對象的List
,來儲存用戶發(fā)布或所寫的文章。
@Data public class UserInfo { private Integer id; private String username; private String password; private String photo; private String createtime; private String updatetime; private Integer state; private List<Articleinfo> aList; }
實現(xiàn)多表查詢的大致過程如下:
- 在Mapper接口中聲明方法,我們聲明一個方法,就是通過用戶id獲取用戶信息以及對應的文章列表。
- 在
xml
文件當中寫resultMap
映射關系,與一對一多表查詢不同的是,我們需要設置collection
標簽,而不是association
標簽。 - 在
xml
文件的resultMap
標簽中至少設置resultMap名字id
,對應映射的類type
等屬性,里面需要設置數(shù)據(jù)表與類中所有字段的映射,以及設置collection
標簽,需要設置property
屬性表示需映射的對象名,設置resultMap即副表的resultMap
路徑,由于你無法保證表與表之間是否存在重名字段,需要設置columnPrefix
為副表的字段添加上一個前綴,防止重名數(shù)據(jù)覆蓋。
<collection property="aList" resultMap="com.example.demo.mapper.ArticleMapper.BaseMap" columnPrefix="a_"> </collection>
在對應的xml
文件當中寫SQL標簽以及語句。
<select id="getUserAndArticlesById" resultMap="BaseMap"> select u.*, a.id as a_id, a.title as a_title, a.content as a_content, a.createtime as a_createtime, a.updatetime as a_updatetime, a.uid as a_uid, a.rcount as a_rcount, a.state as a_state from userinfo as u left join articleinfo as a on u.id=a.uid where u.id=#{uid} </select>
編寫單元測試代碼,測試代碼是否編寫正確。
@Test void getUserAndArticlesById() { Integer id = 1; UserInfo userInfo = userMapper.getUserAndArticlesById(id); log.info("用戶信息:" + userInfo); }
運行結果:
2.動態(tài)SQL
首先來說一下什么是動態(tài)SQL,官方文檔對于動態(tài)SQL的定義是:
動態(tài) SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據(jù)不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最后一個列名的逗號。利用動態(tài) SQL,可以徹底擺脫這種痛苦。使用動態(tài) SQL 并非一件易事,但借助可用于任何 SQL 映射語句中的強大的動態(tài) SQL 語言,MyBatis 顯著地提升了這一特性的易用性。
前面所說的mybatis增刪查改,那些傳入的參數(shù)都是一定會傳入的,但是在實際情況中,很多參數(shù)都是非必傳參數(shù),使用動態(tài)SQL就可以解決傳入的參數(shù)是非必傳參數(shù)的情況。
動態(tài)SQL可以解決多余符號的問題,如,
等。
2.1if標簽
if
標簽的作用就是判斷一個參數(shù)是否有值,如果沒有值就將對應的參數(shù)隱藏。
語法:
<if test="表達式"> sql </if> //例如 <if test="參數(shù)!=null"> sql部分語句 </if>
當表達式為真,則插入if
標簽中的sql
,否則不插入。
我們以在用戶表中插入一條數(shù)據(jù)為例,插入的數(shù)據(jù)中頭像photo
不是必傳的參數(shù):
方法聲明:
//使用動態(tài)sql插入數(shù)據(jù) public int addUser(UserInfo userInfo);
動態(tài)SQL語句:
其中的photo
是非必傳參數(shù),我們使用if
標簽來判斷它是否有值,沒有值就不插入目標的SQL語句。
<insert id="addUser"> insert into userinfo(username, password <if test="photo!=null"> , photo </if> ) values(#{username}, #{password} <if test="photo!=null"> , #{photo} </if> ) </insert>
單元測試代碼:
@Test void addUser() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("張三瘋"); userInfo.setPassword("123456"); int res = userMapper.addUser(userInfo); log.info("受影響的行數(shù)為:" + res); }
在單元測試代碼中,我沒有給photo賦值,if標簽會判斷它為空,不會插入對應photo的SQL,因此插入數(shù)據(jù)photo
為默認值。
結果:
數(shù)據(jù)庫查詢結果:
再來試一試給photo傳值的情況,它生成的SQL有三個參數(shù):
@Test void addUser() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("張無忌"); userInfo.setPassword("12345611"); userInfo.setPhoto("張無忌.png"); int res = userMapper.addUser(userInfo); log.info("受影響的行數(shù)為:" + res); }
運行結果:
最終生成的語句多了一個photo
參數(shù)。
2.2trim標簽
前面所說的if
標簽可以實現(xiàn)非必傳參數(shù)SQL的構造,在極端情況下,有很多個非必傳參數(shù),此時如果只使用if
標簽構造出的SQL語句很有可能會多出一個,
,因為有很多非必傳參數(shù),如果只傳來一個參數(shù),由于不確定后面是否還會有參數(shù),因此會預留一個,
,此時如果沒有其他參數(shù),就會多出一個參數(shù)。
而trim
標簽可以做到這一點,它可以去除SQL語句前后多余的某個字符,它需要搭配if
標簽使用。
<trim>
標簽中有如下屬性:
- prefix:表示整個語句塊,以prefix的值作為前綴
- suffix:表示整個語句塊,以suffix的值作為后綴
- prefixOverrides:表示整個語句塊要去除掉的前綴
- suffixOverrides:表示整個語句塊要去除掉的后綴
語法:
<trim prefix="前綴符", suffix="后綴符", prefixOverrides="去除多余的前綴字符", suffixOverrides="去除多余的后綴字符"> <if test="表達式"> ... </if> ... ... </trim>
假設username
password
photo
都是非必傳參數(shù),但是至少傳遞一個,我們來寫插入語句的動態(tài)SQL。
<insert id="addUser2"> insert into userinfo <trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=","> <if test="username!=null"> username, </if> <if test="password!=null"> password, </if> <if test="photo!=null"> photo </if> </trim> values <trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=","> <if test="username!=null"> #{username}, </if> <if test="password!=null"> #{password}, </if> <if test="photo!=null"> #{photo} </if> </trim> </insert>
單元測試代碼:
@Test void addUser2() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("wangwu"); userInfo.setPassword("12345622"); int res = userMapper.addUser(userInfo); log.info("受影響的行數(shù)為:" + res); }
運行結果與生成的SQL語句:
我們發(fā)現(xiàn)逗號它自動去除了。
2.3where標簽
where
標簽主要是實現(xiàn)where
關鍵字的替換,如果SQL中沒有使用到where
(沒有查詢條件),就會隱藏,存在查詢條件,就會生成含有where的查詢SQL語句,并且可以去除前面的and
。
我們就不以復雜的案例作為演示了,直接寫一個最簡單的查詢,為了簡單,我們刪除數(shù)據(jù)庫的其他數(shù)據(jù),只留admin
一條數(shù)據(jù)。
下面我們來寫最簡單的查詢語句,就是根據(jù)id
獲取一個用戶信息。
寫動態(tài)SQL時,我故意在最前面寫一個and
來證明where
標簽是可以自動刪除前面多余的and
。
<select id="getUserById" resultType="com.example.demo.model.UserInfo"> select * from userinfo <where> <if test="id!=null"> and id=#{id} </if> </where> </select>
單元測試代碼:
@Test void gerUserById() { UserInfo userInfo = userMapper.getUserById(1); System.out.println(userInfo); //Assertions.assertNotNull(userInfo); }
結果:
發(fā)現(xiàn)自動生成了where語句并刪除了多余的and
。
如果我們查詢一個null
值,就不會生成where
語句。
以上<where>
標簽也可以使用 <trim prefix="where" prefixOverrides="and">
替換。
2.4set標簽
其實set
標簽與where
標簽很相似,只不過where
用來替換查詢SQL,set
用于修改SQL中,用來自動生成set
部分的SQL語句。
set
標簽還可以自動去除最后面的一個,
。
比如我們寫一個能夠修改賬戶名username
,密碼password
,頭像photo
的動態(tài)SQL,根據(jù)id
進行修改。
方法聲明:
//使用動態(tài)SQL實現(xiàn)修改用戶信息,包括賬戶名,密碼,頭像 public int updateUser(UserInfo userInfo);
動態(tài)SQL:
<update id="updateUser"> update userinfo <set> <if test="username!=null"> username=#{username}, </if> <if test="password!=null"> password=#{password}, </if> <if test="photo!=null"> photo=#{photo} </if> </set> where id=#{id} </update>
單元測試代碼:
@Test void updateUser() { UserInfo userInfo = new UserInfo(); //修改密碼為123456 userInfo.setPassword("123456"); userInfo.setId(1); int res = userMapper.updateUser(userInfo); log.info("受影響的行數(shù):" + res); }
運行結果:
修改成功并且可以根據(jù)傳入參數(shù)個數(shù)自動生成相應的修改SQL,以及可以自動去除最后的,
。
以上<set>
標簽也可以使用 <trim prefix="set" suffixOverrides=",">
替換。
2.5foreach標簽
對集合進行遍歷可以使用foreach
標簽,常用的場景有批量刪除功能。
- collection:綁定方法參數(shù)中的集合,如 List,Set,Map或數(shù)組對象
- item:遍歷時的每一個對象
- open:語句塊開頭的字符串
- close:語句塊結束的字符串
- separator:每次遍歷之間間隔的字符串
為了方便演示批量刪除,我們隨便插入幾條數(shù)據(jù)到數(shù)據(jù)庫:
方法聲明:
//使用動態(tài)sql批量刪除元素 public int deleteIds(List<Integer> ids);
動態(tài)SQL語句:
<delete id="deleteIds">`在這里插入代碼片` delete from userinfo where id in <foreach collection="ids" open="(" close=")" separator="," item="id"> #{id} </foreach> </delete>
單元測試代碼:
刪除數(shù)據(jù)庫中id
為10 11 12的用戶。
@Test void deleteIds() { List<Integer> ids = new ArrayList<>(); ids.add(10); ids.add(11); ids.add(12); int res = userMapper.deleteIds(ids); log.info("受影響的行數(shù)" + res); }
運行結果:
成功生成了批量刪除的SQL,這就是foreach標簽的作用,它能夠遍歷集合。
總結
到此這篇關于Mybatis多表查詢與動態(tài)SQL特性的文章就介紹到這了,更多相關Mybatis多表查詢與動態(tài)SQL內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
CentOs7 64位 mysql 5.6.40源碼安裝過程
這篇文章主要介紹了CentOs7 64位 mysql-5.6.40源碼安裝過程,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01Windows11下MySQL?8.0.29?安裝配置方法圖文教程
這篇文章主要為大家詳細介紹了Windows11下MySQL?8.0.29?安裝配置方法圖文教程,文中安裝步驟介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07MySQL中將逗號分隔的字段轉換為多行數(shù)據(jù)的方法
在我們的實際開發(fā)中,經常需要存儲一些字段,它們使用像,?-?等連接符進行連接,在查詢過程中,有時需要將這些字段使用連接符分割,然后查詢多條數(shù)據(jù),今天,我們將使用一個實際的生產場景來詳細解釋這個解決方案,需要的朋友可以參考下2024-04-04mysql主鍵,外鍵,非空,唯一,默認約束及創(chuàng)建表的方法
這篇文章主要介紹了mysql主鍵,外鍵,非空,唯一,默認約束及創(chuàng)建表的方法,在數(shù)據(jù)庫中,數(shù)據(jù)表是數(shù)據(jù)庫中最重要、最基本的操作對象,是數(shù)據(jù)存儲的基本單位2022-07-07MySQL5.6升級5.7時出現(xiàn)主從延遲問題排查過程
這篇文章主要介紹了MySQL5.6升級5.7時出現(xiàn)主從延遲問題排查過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09MySQL巧用sum、case和when優(yōu)化統(tǒng)計查詢
這篇文章主要給大家介紹了關于MySQL巧用sum、case和when優(yōu)化統(tǒng)計查詢的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03