MyBatis从入门到精通(八):MyBatis动态Sql之foreach标签的用法
最近在读刘增辉老师所著的《MyBatis从入门到精通》一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸!
本篇博客主要讲解如何使用foreach标签生成动态的Sql,主要包含以下3个场景:
- foreach 实现in集合
- foreach 实现批量插入
- foreach 实现动态update
1. foreach 实现in集合
假设有这样1个需求:根据传入的用户id集合查询出所有符合条件的用户,此时我们需要使用到Sql中的IN,如 id in (1,1001)。
首先,我们在接口SysUserMapper中添加如下方法:
/**
* 根据用户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测试类中添加如下测试方法:
@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();
}
}
运行测试代码,测试通过,输出日志如下:
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.0
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包含属性讲解:
- open:整个循环内容开头的字符串。
- close:整个循环内容结尾的字符串。
- separator:每次循环的分隔符。
- item:从迭代对象中取出的每一个值。
- index:如果参数为集合或者数组,该值为当前索引值,如果参数为Map类型时,该值为Map的key。
- collection:要迭代循环的属性名。
也许有人会好奇,为什么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>
2. 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
3. foreach 实现动态update
假设有这样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>
4. 源码
源码地址:https://github.com/zwwhnly/mybatis-action.git,欢迎下载。
5. 参考
刘增辉《MyBatis从入门到精通》
原文地址:https://www.cnblogs.com/zwwhnly/p/11163638.html
- 显示mybatis的执行的sql
- spring cloud 学习(2) - eureka server注册中心高可用及安全认证
- mybatis在xml文件中处理大于号小于号的方法
- kafka集群部署
- Hadoop(九)Hadoop IO之Compression和Codecs
- 安卓第二夜 有趣的架构
- spring-boot 速成(12) - 如何注入多个redis StringRedisTemplate
- Hadoop(八)Java程序访问HDFS集群中数据块与查看文件系统
- 简明 Git 命令速查表
- spring cloud 学习(8) - sleuth & zipkin 调用链跟踪
- 快速学习Bash
- JavaProblem之hashCode详解
- spring cloud 学习(6) - zuul 微服务网关
- ES6 Features系列:Template Strings & Tagged Template Strings
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- PHP面向对象程序设计中的self、static、parent关键字用法分析
- php实现简单的守护进程创建、开启与关闭操作
- 关于CentOs系统自带python和yum卸载后的解决办法
- php5对象复制、clone、浅复制与深复制实例详解
- Linux命令行快速技巧之定位一个文件的办法
- ubuntu中python调用C/C++办法之动态链接库详解
- linux中使用boost.python调用c++动态库的办法
- 在Linux系统下上传项目到码云的办法
- PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】 原创
- Linux(Ubuntu 18.04)上安装Anaconda步骤详解
- php web环境和命令行环境下查找php.ini的位置
- PHP大文件分块上传功能实例详解
- Linux 命令行通配符及转义符的实现
- Python爬虫抓取指定网页图片代码实例
- PHP变量作用域(全局变量&局部变量)&global&static关键字用法实例分析