在上一节当中我们学习了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();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/46bb1d7d0bc824cb9fe12e345dc6516f.png)
- 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("test@mybatis.tk");
userList.add(user);
}
int result = usermapper.insertList(userList);
}finally{
sqlSession.rollback();
sqlSession.close();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/3debd7f467fecd235b2b41874d60d82c.png)
- 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", "test@mybatis.tk");
map.put("user_password", "12345678");
usermapper.updateByMap(map);
SysUser user = usermapper.selectById(1L);
}finally{
sqlSession.rollback();
sqlSession.close();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/037f797b46fe18d7643e31f1bb8bf1be.png)