關于MyBatis的foreach標簽常用方法
一、前言
在 MyBatis 中,常常會遇到集合類型的參數,雖然我們可以通過 OGNL 表達式來訪問集合的某一個元素,但是 OGNL 表達式無法遍歷集合。foreach 標簽就是專門用來解決這類問題的,foreach 標簽可以用來遍歷數組、列表和 Map 等集合參數,實現批量操作或一些簡單 SQL 操作。
二、foreach 元素屬性簡介
foreach 元素的屬性主要有 item,index,open,separator,close,collection。各屬性含義如下所示。
2.1 item
集合中元素迭代時的別名,該參數為必選。
2.2 index
在 list 和數組中,index 是元素的序號;在 map 中,index 是元素的 key。該參數可選。
2.3 open
foreach 代碼的開始符號,一般是 ”(“,和 close=“)” 合用。常用在 in(),values() 時。該參數可選。
2.4 separator
元素之間的分隔符,例如在 in() 的時候,separator=“,” 會自動在元素中間用 “,“ 隔開,避免手動輸入逗號導致 SQL 錯誤,如 in(1, 2,) 這樣。該參數可選。
2.5 close
foreach 代碼的關閉符號,一般是 ”)“,和 open=“(” 合用。常用在 in(),values()時。該參數可選。
2.6 collection
要被 foreach 標簽循環(huán)解析的對象。
foreach 標簽的 collection 屬性在接受參數名時,有兩種情況:
- 匿名參數
當在 java 方法中沒有通過 @Param 注解指定參數名時,列表類型默認參數名為 ”list“,數組類型默認參數名為 ”array“,Map 對象沒有默認值。 - 具名參數
java 方法中使用了 @Param 注解指定了參數名稱,則 foreach 中的 collection 屬性必須為參數名。
在作為入參時可以使用 @Param(“keyName”) 來設置該鍵值,設置 keyName 后,list、array 將會失效。除了入參這種情況外,還有一種是作為參數對象的某個字段,例子如下。如果 User 有屬性 List ids。入參是 User 對象,那么這個collection = “ids”。如果 User 有屬性 Ids ids,其中 Ids 是個對象,Ids 有個屬性 List id,入參是 User 對象,那么 collection = “ids.id”。
注意點:在使用 foreach 的時候,最關鍵的就是 collection 屬性,該屬性是必須指定的,但是在不同情況下,該屬性的值是不一樣的,主要有以下 3 種情況(未通過 @Param 指定別名時)。
- 如果傳入的是單參數且參數類型是一個 List 的時候,collection 屬性值為 ”list“。
- 如果傳入的是單參數且參數類型是一個 array 數組的時候,collection 的屬性值為 ”array“。
- 如果傳入的參數是多個的時候,我們可以把它們封裝成一個 Map,當然單參數也可以封裝成 map。實際上如果你在傳入參數的時候,在 MyBatis 里面也是會把它封裝成一個 Map 的,map 的 key 就是參數名,所以這個時候 collection 屬性值就是傳入的 List 或 array 對象在自己封裝的 map 里面的 key。
三、#{} 與 ${} 的區(qū)別
在使用參數的過程中,會遇到 #{} 與 ${} 的問題,因此簡單總結下兩者之間的區(qū)別。
- ${param} 傳遞的參數會被當成 SQL 語句中的一部分,比如傳遞表名,字段名,字段類型等數據。 例如,傳入值為 id,order by ${param} 則解析成 SQL:order by id。
- #{parm} 傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。 例如,傳入值為 id,select * from table where name = #{param} 則解析成 SQL:select * from table where name = ? (其中問號在執(zhí)行時傳入值 “id”)。
為了安全,能用 # 的地方就用 # 方式傳參,這樣可以有效的防止 SQL 注入攻擊。
官方說明:mybatis 在處理 #{} 時,會將 SQL 中的 #{} 替換為 “?”,調用 PreparedStatement 的 set 方法來賦值;mybatis 在處理 ${} 時,就是把 ${} 替換成變量的值。使用 #{} 可以有效的防止 SQL 注入,提高系統(tǒng)安全性。
四、實例實戰(zhàn)
本文以如下幾個例子簡單總結下 foreach 是如何遍歷列表、數組和 Map 的。
4.1 遍歷 List<String> 列表
Java 層接口
List<Rule> selectRulesByList(List<String> ids);
XML
<select id="selectRulesByList" resultMap="BaseResultMap"> SELECT <include refid="Base_Column_List" /> FROM tbl_test_rule WHERE rule_id IN <foreach collection="list" open="(" close=")" separator="," item="item" index="index"> #{item} </foreach> </select>
運行時 SQL 語句
==> Preparing: SELECT rule_id, rule_name, rule_type FROM tbl_test_rule WHERE rule_id IN ( ? , ? ) ==> Parameters: 10001(String), 20002(String) <== Total: 2
4.2 遍歷 List<Object> 列表
項目中定義了一個實體類 Rule,在批量插入時需要遍歷 List<Rule>,實現方式見下文。
Java 層接口
int insertRules(@Param("rules") List<Rule> rules);
XML
<insert id="insertRules"> INSERT INTO tbl_test_rule (rule_id, rule_name, rule_type) VALUES <foreach collection="rules" separator="," item="rule"> (#{rule.ruleId}, #{rule.ruleName}, #{rule.ruleType}) </foreach> </insert>
運行時 SQL 語句
==> Preparing: INSERT INTO tbl_test_rule (rule_id, rule_name, rule_type) VALUES (?, ?, ?) , (?, ?, ?) ==> Parameters: ruleId1(String), ruleName1(String), 1(String), ruleId2(String), ruleName2(String), 2(String) <== Updates: 2
4.3 遍歷數組
Java 層接口
List<Rule> selectRulesByArray(String[] ids);
如果 ids 參數使用 @Param 注解指定了參數名稱,則 foreach 標簽中的 collection 屬性必須為該名稱;但若未指定名稱,則在 foreach 標簽中使用默認數組名稱 array,如下所示
XML
<select id="selectRulesByArray" resultMap="BaseResultMap"> SELECT <include refid="Base_Column_List" /> FROM tbl_test_rule WHERE rule_id IN <foreach collection="array" open="(" close=")" separator="," item="item" index="index"> #{item} </foreach> </select>
運行時 SQL 語句
==> Preparing: SELECT rule_id, rule_name, rule_type FROM tbl_test_rule WHERE rule_id IN ( ? , ? ) ==> Parameters: 10001(String), 20002(String) <== Total: 2
4.4 遍歷 Map 實現 insert into … on duplicate key update
數據庫表 tbl_test_discount,聯(lián)合主鍵(cert_no, rule_id, cycle_id),存儲了不同用戶不同周期下的折扣金額。請求參數 Map 中存儲了某一用戶不同規(guī)則(key 為不同的 rule_id 值)和各個規(guī)則下的折扣值(value 為 dis_sum),如下方 Java 接口定義。需要實現:當數據庫中無主鍵記錄時,將記錄插入數據庫;如數據庫中存在主鍵記錄時,更新折扣值,將折扣值累加計算(即實現 insert into … on duplicate key update 操作)。過程示例如下。
Java 層接口
int saveOrUpd(@Param(value = "certNo") String certNo, @Param(value = "cycleId") String cycleId, @Param(value = "params") Map map);
使用 foreach 標簽遍歷 Map 時,collection 屬性值為 @param 注解指定的參數名,即 params,且 item 是 Map 的鍵值,index 是鍵名。
XML
<update id="saveOrUpd" parameterType="java.util.Map"> <foreach collection="params" index="key" item="value"> insert into tbl_test_discount (cert_no, rule_id, cycle_id, dis_sum) values (#{certNo}, #{key}, #{cycleId}, #{value}) on duplicate key update dis_sum = dis_sum + #{value}; </foreach> </update>
mybatis 設置允許批量更新
mybatis 會根據上述 XML 文件的配置,動態(tài)生成多條 SQL。要讓 mybatis 成功執(zhí)行多條語句,須開啟允許批量查詢設置,即在 jdbc-url 連接信息中添加 &allowMultiQueries=true,如下所示。
spring.datasource.jdbc-url=jdbc:mysql://localhost:3306/testdb?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
MySQL 連接數據庫時,添加語句 &allowMultiQueries=true
的作用:可以在 SQL 語句后攜帶分號,實現多語句執(zhí)行;可以執(zhí)行批處理,同時發(fā)出多個 SQL 語句。
運行時 SQL 語句
==> Preparing: insert into tbl_test_discount (cert_no, rule_id, cycle_id, dis_sum) values (?, ?, ?, ?) on duplicate key update dis_sum = dis_sum + ?; insert into tbl_test_discount (cert_no, rule_id, cycle_id, dis_sum) values (?, ?, ?, ?) on duplicate key update dis_sum = dis_sum + ?; insert into tbl_test_discount (cert_no, rule_id, cycle_id, dis_sum) values (?, ?, ?, ?) on duplicate key update dis_sum = dis_sum + ?; insert into tbl_test_discount (cert_no, rule_id, cycle_id, dis_sum) values (?, ?, ?, ?) on duplicate key update dis_sum = dis_sum + ?; ==> Parameters: testCertNo1(String), 30001(String), 202212(String), 225(Integer), 225(Integer), testCertNo2(String), 20002(String), 202212(String), 385(Integer), 385(Integer), testCertNo3(String), 20001(String), 202212(String), 553(Integer), 553(Integer), testCertNo4(String), 10001(String), 202212(String), 300(Integer), 300(Integer) <== Updates: 1
foreach 標簽是使用非常廣泛的一個標簽,當使用 SQL 進行批量插入、查詢時都可能使用到它。列表遍歷的使用最為廣泛,數組和 Map 則相對較少。
到此這篇關于關于MyBatis的foreach標簽常用方法的文章就介紹到這了,更多相關MyBatis的foreach標簽內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
myeclipse安裝Spring Tool Suite(STS)插件的方法步驟
這篇文章主要介紹了myeclipse安裝Spring Tool Suite(STS)插件的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08解決springboot?druid數據庫連接池連接失敗后一直重連問題
這篇文章主要介紹了解決springboot?druid數據庫連接池連接失敗后一直重連問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11ShardingSphere結合MySQL實現分庫分表的項目實踐
在實際開發(fā)中,如果表的數據過大我們需要把一張表拆分成多張表,本文主要介紹了使用ShardingSphere實現MySQL分庫分表,具有一定的參考價值,感興趣的可以了解一下2024-03-03@RequestBody,@RequestParam和@Param的區(qū)別說明
這篇文章主要介紹了@RequestBody,@RequestParam和@Param的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03