Mybatis學習日記(五)——動態SQL第二部分

在上一節當中我們學習了Mybatis動態SQL中的if,choose(when、otherwise),trim(where、set)幾種標籤,接下來將詳細講解剩下的兩種標籤foreach和bind。


一.foreach用法

foreach可以對數組、Map或實現了Iterable接口的對象進行遍歷,在很多情況下都能用到這個標籤,我們將通過3個不同的例子介紹該標籤。首先我們設計一個根據用戶id集合查詢的方法,添加selectByIdList方法及對應的動態SQL語句

/**
* 根據用戶ID集合查詢
* 
* @param idList
* @return
* */
List<SysUser> selectByIdList(@Param("idList")List<Long> idList);
<select id="selectByIdList" resultType="sysUser">
	select id,
		user_name userName,
		user_password userPassword,
		user_email userEmail,
		user_info userInfo,
		head_img headImg,
		create_time createTime
	from sys_user
	where id in
	<foreach collection="idList" open="(" close=")" separator="," item="id" index="i">
		#{id}
	</foreach>
</select>

其中的collection屬性值爲要迭代循環的屬性名,這個屬性名的情況有很多,如果參數類型爲List時,默認爲list;如果參數類型是數組,默認爲array;如果參數類型爲map,默認則爲_Parameter。所以我們通常建議使用@Param來指定參數名,這時collection的值爲通過@Param註解指定的名字,同時可以解決多個參數的麻煩。

item屬性爲從迭代對象中取出的每一個值;index爲索引的屬性名,在集合和數組的情況下爲當前索引值,在map情況下值爲map的key;open屬性爲整個循環內容開頭的字符串;close屬性爲整個循環內容結尾的字符串;separator爲每次循環的分隔符。

通過對foreach標籤內各個屬性的講解,我們來看看另外兩個例子是如何使用foreach的。我們創建一個insertList方法用來實現數據庫的批量插入(要實現此功能前提是數據庫支持批量插入),批量插入的語法如下:

INSERT INTO tablename (column-a,[column-b, ...])
VALUES ('value-1a',['value-1b', ...]),
       ('value-2a',['value-2b', ...]),
       ...

我們添加如下動態SQL語句:

/**
* 批量插入用戶信息
* 
* @param userList
* @return 
* */
int insertList(@Param("userList")List<SysUser> userList);
<insert id="insertList">
	insert into         
    sys_user(user_name,user_password,user_email
            ,user_info,head_img,create_time)
	values
	<foreach collection="userList" item="user" separator=",">
		(
		#{user.userName},#{user.userPassword},#{user.userEmail},
		#{user.userInfo},#{user.headImg, jdbcType=BLOB},
		#{user.createTime, jdbcType=TIMESTAMP}
		)
	</foreach>
</insert>

可以看到,通過item指定了循環變量名後,在引用時使用的是“屬性.屬性”的方法。最後我們在實現一個方法updateByMap來實現動態update。添加該方法和動態SQL語句如下:

/**
* 通過Map更新列
* 
* @param map
* @return
* */
int updateByMap(@Param("map") Map<String, Object> map);
<update id="updateByMap">
	update sys_user
	set
	<foreach collection="map" item="val" index="key" separator=",">
		${key} = #{val}
	</foreach>
	where id = #{val}
</update>

需要注意的是,參數爲map時,index對應的不是索引值,而是map中的key,故而可以使用它作爲需要更新的列名。


二.bind用法

bind標籤的使用場景並不多,它的作用主要是爲了防止數據庫的變更。各個數據庫之間的語法是由差異的,如果更換數據庫,有些SQL語句可能需要重寫,而使用bind標籤可以儘可能避免這種情況。在上一節中我們有一個selectByUser方法中用到了like查詢條件,代碼如下:

<if test="userName != null and userName != ''">
and user_name like concat('%',#{userName},'%');
</if>

再使用bind標籤之後如下所示:

<if test="userName != null and userName != ''">
    <bind name="userNameLike" value="'%' + userName + '%'"/>
    and user_name like #{userNameLike}
</if>

bind標籤有name和value兩個屬性,name爲綁定到上下文的變量名,value爲表達式,通過bind標籤,能儘可能避免因更換數據庫而修改SQL,也能預防SQL注入。


三.其他介紹

通過bind標籤並不能解決所有更換數據庫帶來的問題,所以還有一種方法,通過Mybatis提供的databaseIdProvider多數據庫配置,這種配置時基於映射與居中的databaseId屬性的。如果需要用到,我們需要在mybatis-config.xml配置文件中加入如下配置:

<databaseIdProvider type="DB_VENDOR">
    <property name="SQL Server" value="sqlserver"/>
    <property name="DB2" value="db2"/>
    <property name="Oracle" value="oracle"/>
    <property name="MySQL" value="mysql"/>
    <property name="PostgreSQL" value="postgresql"/>
    <property name="Derby" value="derby"/>
    <property name="HSQL" value="hsqldb"/>
    <property name="H2" value="h2"/>
</databaseIdProvider>

這樣配置之後,databaseId將被設置爲第一個能匹配數據庫名稱對應的value值,舉個例子來說明一下怎樣使用databaseId屬性。我們修改selectByUser方法如下:


四.測試結果

我們將根據從上之下的順序將本篇文章中介紹的所有方法的測試方法及其結果展示出來。

  • selectByIdList
@Test
public void testSelectByIdList(){
	SqlSession sqlSession = getSqlSession();
	try{
		UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
		List<Long> idList = new ArrayList<Long>();
		idList.add(1L);
		idList.add(1001L);
			
		List<SysUser> userList = usermapper.selectByIdList(idList);
	}finally{
		sqlSession.close();
	}
}
selectByIdList測試結果

 

  • insertList
@Test
public void testInsertList(){
	SqlSession sqlSession = getSqlSession();
	try{
		UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
			
		List<SysUser> userList = new ArrayList<SysUser>();
		for(int i=0;i<2;i++)
		{
			SysUser user = new SysUser();
			user.setUserName("test"+i);
			user.setUserPassword("123456");
			user.setUserEmail("[email protected]");
			userList.add(user);
		}
			
		int result = usermapper.insertList(userList);
			
	}finally{
		sqlSession.rollback();
		sqlSession.close();
	}
}
insertList測試結果

 

  • updateByMap
@Test
public void testUpdateByMap(){
	SqlSession sqlSession = getSqlSession();
	try{
		UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
			
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("id", 1L);
		map.put("user_email", "[email protected]");
		map.put("user_password", "12345678");
		usermapper.updateByMap(map);
			
		SysUser user = usermapper.selectById(1L);
	}finally{
		sqlSession.rollback();
		sqlSession.close();
	}
}
updateByMap測試結果

上一篇:Mybatis學習日記(四)——動態SQL第一部分

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章