一、写在前面
MyBatis 动态 SQL 的一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。foreach
允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。foreach
是动态 SQL 中一个非常强大的标签。下面就来体验一下foreach
标签带来的便捷之处,有关批量操作的实现,这里以批量插入数据为例。
二、foreach
遍历传递进来的集合
有时候我们可能会有下面的需求,根据多个 id 查询对应的信息,这多个 id 的数量是不固定的。
SELECT * FROM t_employee
WHERE id IN (1, 2, 3, ...)
这时候我们可以通过使用foreach
标签来遍历集合中的参数,完成多个 id 之间的拼接。
mapper 接口:
/** 根据传入的 id 集合,查询出对应的员工信息,并使用集合保存信息 */
List<Employee> getEmpsByConditions(@Param("list") List<Integer> idList);
SQL 映射文件:
<!-- 注意返回的数据类型是集合中保存的数据类型 Employee-->
<select id="getEmpsByConditions" resultType="com.jas.mybatis.bean.Employee">
SELECT * FROM t_employee WHERE id IN
<!--
collection:指定要遍历的集合
item:取出当前集合中元素,赋给 item 中的值
separator:遍历出的多个元素之间用什么分隔符分隔开
open:遍历集合前用什么字符进行拼接
close:遍历集合后用什么字符进行拼接
在 foreach 标签中还有一个属性 index,
遍历集合的时候 index 表示的是当前元素的索引,item 对应索引中的值
遍历 map 的时候 index 表示的是当前 map 中的 key,item 是 key 对应的 value
-->
<foreach collection="list" item="empId" separator="," open="(" close=")">
#{empId}
</foreach>
</select>
测试代码:
// 用于返回 SqlSession 对象
private SqlSession getSqlSession() throws IOException {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
@Test
public void testList() throws IOException {
SqlSession sqlSession = getSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> list = employeeMapper.getEmpsByConditions(Arrays.asList(1,2,15));
for(Employee employee : list){
System.out.println(employee);
}
sqlSession.close();
}
执行结果:
三、foreach
批量插入数据
实现foreach
批量插入数据有两种方法,一种是只发送一条 SQL,插入的多条数据之间通过”,
” 分隔开,另一种方式是每插入一条数据就发送一条 SQL 语句,多个 SQL 语句之间用”;
“分割。
3.1 一条 SQL 批量插入数据
mapper 接口:
/** 返回值为 Integer 类型 */
Integer addEmpsByList(@Param("list") List<Employee> list);
SQL 映射文件:
<insert id="addEmpsByList" parameterType="com.jas.mybatis.bean.Employee">
INSERT INTO t_employee(username, gender, email) VALUES
<foreach collection="list" item="emp" separator=",">
(#{emp.username}, #{emp.gender}, #{emp.email})
</foreach>
</insert>
测试代码:
@Test
public void testBatchAdd() throws IOException {
SqlSession sqlSession = getSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> List = new ArrayList<>();
List.add(new Employee(null, "Jas", '1', "fsd54@qq.com"));
List.add(new Employee(null, "Jason", '0', "456jhk@qq.com"));
employeeMapper.addEmpsByList(List);
sqlSession.commit();
sqlSession.close();
}
执行结果:
3.2 执行多条 SQL 批量插入数据
修改对应的 SQL 映射文件中的 SQL:
<insert id="addEmpsByList" parameterType="com.jas.mybatis.bean.Employee">
<!--
每插入一条数据就执行一次 SQL,中间用";"分隔开
-->
<foreach collection="list" item="emp" separator=";">
INSERT INTO t_employee(username, gender, email) VALUES
(#{emp.username}, #{emp.gender}, #{emp.email})
</foreach>
</insert>
MySql 默认的情况下是不支持使用”;
” 分隔开多条 SQL 进行执行的,需要设置一个连接属性allowMultiQueries=true
来支持。可以在连接数据库的时候设置这个属性。
jdbc.url=jdbc:mysql://localhost:3306/mybatis-study?allowMultiQueries=true
测试代码:
@Test
public void testBatchAdd() throws IOException {
SqlSession sqlSession = getSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> List = new ArrayList<>();
List.add(new Employee(null, "Tom", '1', "fd@qq.com"));
List.add(new Employee(null, "Tony", '0', "456fdfjhk@qq.com"));
employeeMapper.addEmpsByList(List);
sqlSession.commit();
sqlSession.close();
}
执行结果:
四、总结
这篇博文主要对 MyBati 动态 SQL 中的foreach
进行了介绍与其使用场景的应用,MyBatis 还提供了其他的标签来支持动态 SQL。比如:if
、choose (when, otherwise)
、trim (where, set)
,有关的详细信息可以到官方文档进行深入了解,希望这篇博文能够为你提供一些帮助。
动态 SQL 官方文档链接:
http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html