本篇博客主要讲解如何使用foreach标签生成动态的Sql,主要包含如下3个场景:html
假设有这样1个需求:根据传入的用户id集合查询出全部符合条件的用户,此时咱们须要使用到Sql中的IN,如 id in (1,1001)。java
首先,咱们在接口SysUserMapper中添加以下方法:git
/** * 根据用户id集合查询用户 * * @param idList * @return */ List<SysUser> selectByIdList(List<Long> idList);
而后在对应的SysUserMapper.xml中添加以下代码:程序员
<select id="selectByIdList" resultType="com.zwwhnly.mybatisaction.model.SysUser"> SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id IN <foreach collection="list" open="(" close=")" separator="," item="id" index="i"> #{id} </foreach> </select>
最后,在SysUserMapperTest测试类中添加以下测试方法:github
@Test public void testSelectByIdList() { SqlSession sqlSession = getSqlSession(); try { SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class); List<Long> idList = new ArrayList<Long>(); idList.add(1L); idList.add(1001L); List<SysUser> userList = sysUserMapper.selectByIdList(idList); Assert.assertEquals(2, userList.size()); } finally { sqlSession.close(); } }
运行测试代码,测试经过,输出日志以下:sql
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id IN ( ? , ? )数据库
DEBUG [main] - ==> Parameters: 1(Long), 1001(Long)数组
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time微信
TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0mybatis
TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 2
经过日志会发现,foreach元素中的内容最终生成的Sql语句为(1,1001)。
foreach包含属性讲解:
也许有人会好奇,为何collection的值是list?该值该如何设置呢?
上面的例子中只有一个集合参数,咱们把collection属性的值设置为了list,其实也能够写成collection,为何呢?让咱们看下DefaultSqlSession中的默认处理逻辑:
private Object wrapCollection(Object object) { DefaultSqlSession.StrictMap map; if (object instanceof Collection) { map = new DefaultSqlSession.StrictMap(); map.put("collection", object); if (object instanceof List) { map.put("list", object); } return map; } else if (object != null && object.getClass().isArray()) { map = new DefaultSqlSession.StrictMap(); map.put("array", object); return map; } else { return object; } }
虽然使用默认值,代码也能够正常运行,但仍是推荐使用@Param来指定参数的名字,以下所示:
List<SysUser> selectByIdList(@Param("idList") List<Long> idList);
<foreach collection="idList" open="(" close=")" separator="," item="id" index="i"> #{id} </foreach>
若是参数是一个数组参数,collection能够设置为默认值array,看了上面的源码,应该不难理解。
/** * 根据用户id数组查询用户 * * @param idArray * @return */ List<SysUser> selectByIdArray(Long[] idArray);
<select id="selectByIdArray" resultType="com.zwwhnly.mybatisaction.model.SysUser"> SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id IN <foreach collection="array" open="(" close=")" separator="," item="id" index="i"> #{id} </foreach> </select>
虽然使用默认值,代码也能够正常运行,但仍是推荐使用@Param来指定参数的名字,以下所示:
List<SysUser> selectByIdArray(@Param("idArray")Long[] idArray);
<foreach collection="idArray" open="(" close=")" separator="," item="id" index="i"> #{id} </foreach>
假设有这样1个需求:将传入的用户集合批量写入数据库。
首先,咱们在接口SysUserMapper中添加以下方法:
/** * 批量插入用户信息 * * @param userList * @return */ int insertList(List<SysUser> userList);
而后在对应的SysUserMapper.xml中添加以下代码:
<insert id="insertList" useGeneratedKeys="true" keyProperty="id"> INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time) VALUES <foreach collection="list" item="user" separator=","> (#{user.userName},#{user.userPassword},#{user.userEmail},#{user.userInfo},#{user.headImg,jdbcType=BLOB},#{user.createTime,jdbcType=TIMESTAMP}) </foreach> </insert>
最后,在SysUserMapperTest测试类中添加以下测试方法:
@Test public void testInsertList() { SqlSession sqlSession = getSqlSession(); try { SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class); List<SysUser> sysUserList = new ArrayList<SysUser>(); for (int i = 0; i < 2; i++) { SysUser sysUser = new SysUser(); sysUser.setUserName("test" + i); sysUser.setUserPassword("123456"); sysUser.setUserEmail("test@mybatis.tk"); sysUserList.add(sysUser); } int result = sysUserMapper.insertList(sysUserList); for (SysUser sysUser : sysUserList) { System.out.println(sysUser.getId()); } Assert.assertEquals(2, result); } finally { sqlSession.close(); } }
运行测试代码,测试经过,输出日志以下:
DEBUG [main] - ==> Preparing: INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time) VALUES (?,?,?,?,?,?) , (?,?,?,?,?,?)
DEBUG [main] - ==> Parameters: test0(String), 123456(String), test@mybatis.tk(String), null, null, null, test1(String), 123456(String), test@mybatis.tk(String), null, null, null
DEBUG [main] - <== Updates: 2
1035
1036
假设有这样1个需求:根据传入的Map参数更新用户信息。
首先,咱们在接口SysUserMapper中添加以下方法:
/** * 经过Map更新列 * * @param map * @return */ int updateByMap(Map<String, Object> map);
而后在对应的SysUserMapper.xml中添加以下代码:
<update id="updateByMap"> UPDATE sys_user SET <foreach collection="_parameter" item="val" index="key" separator=","> ${key} = #{val} </foreach> WHERE id = #{id} </update>
最后,在SysUserMapperTest测试类中添加以下测试方法:
@Test public void testUpdateByMap() { SqlSession sqlSession = getSqlSession(); try { SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.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"); Assert.assertEquals(1, sysUserMapper.updateByMap(map)); SysUser sysUser = sysUserMapper.selectById(1L); Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail()); Assert.assertEquals("12345678", sysUser.getUserPassword()); } finally { sqlSession.close(); } }
运行测试代码,测试经过,输出日志以下:
DEBUG [main] - ==> Preparing: UPDATE sys_user SET user_email = ? , user_password = ? , id = ? WHERE id = ?
DEBUG [main] - ==> Parameters: test@mybatis.tk(String), 12345678(String), 1(Long), 1(Long)
DEBUG [main] - <== Updates: 1
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1, admin, 12345678, test@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 1
上面示例中,collection使用的是默认值_parameter,也能够使用@Param指定参数名字,以下所示:
int updateByMap(@Param("userMap") Map<String, Object> map);
<update id="updateByMap"> UPDATE sys_user SET <foreach collection="userMap" item="val" index="key" separator=","> ${key} = #{val} </foreach> WHERE id = #{userMap.id} </update>
源码地址:https://github.com/zwwhnly/mybatis-action.git,欢迎下载。
刘增辉《MyBatis从入门到精通》
原创不易,若是以为文章能学到东西的话,欢迎点个赞、评个论、关个注,这是我坚持写做的最大动力。
若是有兴趣,欢迎添加个人微信:zwwhnly,等你来聊技术、职场、工做等话题(PS:我是一名奋斗在上海的程序员)。
原文出处:https://www.cnblogs.com/zwwhnly/p/11163638.html