考虑以下场景:
InfoTable(信息表):
Name | Gender | Age | Score |
---|---|---|---|
张三 | 男 | 21 | 90 |
李四 | 女 | 20 | 87 |
王五 | 男 | 22 | 92 |
赵六 | 女 | 19 | 94 |
孙七 | 女 | 23 | 88 |
周八 | 男 | 20 | 91 |
StatusTable(状态表,指是否有在考试之前复习):
Name | hasReview |
---|---|
张三 | 是 |
李四 | 否 |
王五 | 是 |
赵六 | 是 |
孙七 | 否 |
周八 | 是 |
现在,我想知道所有复习过的学生的成绩,可以利用mysql中的子查询来实现:
SELECT Score
FROM InfoTable
WHERE Name in (SELECT Name
FROM StatusTable
WHERE hasReview = '是');
这种方式非常方便,我们只要把查询条件写出来,剩下的操作都由mysql来处理。而在实际场景中,为了减少底层耦合,我们一般不通过mysql中的子查询方式联表查询,而是先执行子查询得到结果集,再以结果集作为条件执行外层查询。通常情况下,子查询和外层查询由上层的不同服务执行,这样就在一定程度上达到了底层数据库解耦的目的。注意这种实现方式将mysql内部的一部分复杂操作抛给了我们。这时,Mybatis中的foreach
标签就有了用武之地。
foreach
标签的用法还以刚才的例子来说,先执行子查询
SELECT Name FROM StatusTable WHERE hasReview = '是'
再执行外层查询,就是
SELECT Score
FROM InfoTable
WHERE Name in ('张三' , '王五', '赵六', '周八');
也就是一个批量查询操作,将其抽象一下(假设有三个条件):
SELECT *
FROM <tableName>
WHERE <ColumnName> IN (<case1>,<case2>,<case3>)
实际情况中,case可能远不止3个,这时可以在XXXMapper.xml文件中利用Mybatis中的foreach
编写sql语句:
SELECT *
FROM <tableName>
WHERE <ColumnName> IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
就可以实现相同的效果了。
那么问题来了,foreach
标签中各种参数是什么含义呢?
(
,就对应于IN (<case1>,<case2>,<case3>)
中IN后面的第一个(
,
,就对应于IN (<case1>,<case2>,<case3>)
中的,
)
,就对应于IN (<case1>,<case2>,<case3>)
中<case3>
后面的)
Mybatis中属性的含义 之 collection 1.eg: <select id="getEmpsInNames" resultType="emp"> select * from emp where ename in <foreach collection="list" index="index" item="name" open="(" separator="," close=")"> #{name} </foreach> </select> 对应的测试代码: @Test public void dynamicForeachTest() { SqlSession session = Util.getSqlSessionFactory().openSession(); BlogMapper blogMapper = session.getMapper(BlogMapper.class); List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(3); ids.add(6); List<Blog> blogs = blogMapper.dynamicForeachTest(ids); for (Blog blog : blogs) System.out.println(blog); session.close(); } 2.eg: <select id="dynamicForeach2Test" resultType="Blog"> select * from t_blog where id in <foreach collection="array" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select> 对应的测试代码: @Test public void dynamicForeach2Test() { SqlSession session = Util.getSqlSessionFactory().openSession(); BlogMapper blogMapper = session.getMapper(BlogMapper.class); int[] ids = new int[] {1,3,6,9}; List<Blog> blogs = blogMapper.dynamicForeach2Test(ids); for (Blog blog : blogs) System.out.println(blog); session.close(); } 3.eg: 自己把参数封装成Map的类型 <select id="dynamicForeach3Test" resultType="Blog"> select * from t_blog where title like "%"#{title}"%" and id in <foreach collection="ids" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select> 上述collection的值为ids,是传入的参数Map的key,对应的Mapper代码: public List dynamicForeach3Test(Map<String, Object> params); 对应测试代码: @Test public void dynamicForeach3Test() { SqlSession session = Util.getSqlSessionFactory().openSession(); BlogMapper blogMapper = session.getMapper(BlogMapper.class); final List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(2); ids.add(3); ids.add(6); ids.add(7); ids.add(9); Map<String, Object> params = new HashMap<String, Object>(); params.put("ids", ids); params.put("title", "中国"); List<Blog> blogs = blogMapper.dynamicForeach3Test(params); for (Blog blog : blogs) System.out.println(blog); session.close(); }