[一步是咫尺,一步即天涯]
本文,我们来介绍使用Mybatis提供的<foreach>标签实现我们某些循环增改删差的需求。官方文档中的内容过于简陋,于是,博主筛选出比较全面讲述foreach用法的的内容,并且配有例子。希望各位看官能够手动敲一遍下面的例子,达到快速学习的目的。
准备工作:
a.操作系统 :win7 x64
b.基本软件:MySQL,Mybatis,SQLyog
--------------------------------------------------------------------------------------------------------------------------------------------------------
属性 |
描述 |
item |
循环体中的具体对象。支持属性的点路径访问,如item.age,item.info.details。 具体说明:在list和数组中是其中的对象,在map中是value。 该参数为必选。 |
collection |
要做foreach的对象,作为入参时,List<?>对象默认用list代替作为键,数组对象有array代替作为键,Map对象没有默认的键。 当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子: 如果User有属性List ids。入参是User对象,那么这个collection = "ids" 如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id" 上面只是举例,具体collection等于什么,就看你想对那个元素做循环。 该参数为必选 |
separator |
元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。 |
open |
foreach代码的开始符号,一般设置为“(“和close=")"合用。常用在in(),values()时。该参数可选。 |
close |
foreach代码的关闭符号,一般设置为“)“和open="("合用。常用在in(),values()时。该参数可选。 |
index |
在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。【这个具体用法见下文】 |
--------------------------------------------------------------------------------------------------------------------------------------------------------
【本文我们将给出完整的工程代码,请读者一定在本地运行一遍,加深理解】
1.首先,创建我们的Spring09工程,工程结构图如下:
2.pom文件内容如下:
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.26</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=12344.日志配置文件log4j.properties内容如下:
log4j.rootLogger=debug,stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n5.mybatis-config.xml配置文件内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="jdbc.properties"/> <settings> <setting name="logImpl" value="LOG4J"/> </settings> <typeAliases> <package name="com.csdn.ingo.entity"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="mappers/UserInfoMapper.xml"/> <mapper resource="mappers/UserMapper.xml"/> </mappers> </configuration>6.UserInfo.java文件内容如下:
@SuppressWarnings("serial") public class UserInfo implements Serializable { private String userid; private String department; private String position; private String mobile; private String gender; private String email; private Departments depart; //set,get,构造函数,toString,请自行补充 }7.user.java文件内容如下:
@SuppressWarnings("serial") public class User implements Serializable{ private String id; private String password; //set,get,构造函数,toString,请自行补充} 8.SqlSessionFactoryUtil.java内容如下:
package com.csdn.ingo.util; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SqlSessionFactoryUtil { private static SqlSessionFactory sqlSessionFactory; public static SqlSessionFactory getSqlSessionFactory(){ if(sqlSessionFactory==null){ InputStream inputStream=null; try{ inputStream=Resources.getResourceAsStream("mybatis-config.xml"); sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); }catch(Exception e){ e.printStackTrace(); } } return sqlSessionFactory; } public static SqlSession openSession(){ return getSqlSessionFactory().openSession(); } }--------------------------------------------------------------------------------------------------------------------------------
准备工作结束,马上开始我们的<foreach>讲解,请睁大眼见哦!
--------------------------------------------------------------------------------------------------------------------------------
1.UserTest的单元测试方法为:
@Test public void testForEachArray() { try { String[] sa = new String[]{"admin","customer","customer2"}; UserInfoDao userInfo = sqlSession.getMapper(UserInfoDao.class); List<UserInfo> UIList = userInfo.selectUserInfoByForEachArray(sa); for (UserInfo ui : UIList) { System.out.println(ui.toString()); } } catch (Exception e) { e.printStackTrace(); } }
【注意】
public interface UserInfoDao { List<UserInfo> selectUserInfoByForEachArray(String[] sa); }3.UserInfoMapper.xml的内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.csdn.ingo.dao.UserInfoDao"> <resultMap type="userInfo" id="UserInfoResult"> <id property="userid" column="userid" /> <result property="department" column="department" /> <result property="position" column="position" /> <result property="mobile" column="mobile" /> <result property="gender" column="gender" /> <result property="email" column="email" /> </resultMap> <select id="selectUserInfoByForEachArray" resultMap="UserInfoResult"> select * from userinfo <if test="array!=null"> where userid in <foreach item="item" collection="array" index="index" open="(" separator="," close=")"> #{item} </foreach> </if> </select> </mapper>
【解释】
a。这里的if标签能够判断出数组是否为空。但是没有判断出数组中的内容是否为空。即,当数组中有内容时或者数组为null时,该SQL语句能够正常执行,但是如果数组为空的话,if判断的结果为真,但foreach执行0次。这种情况下,Mybatis会组装出1条错误的sql语句。换句话说这里if是多余的。
b。这里collection属性配置为”array“
c。index在这条语句中未使用,所以是可以缺省的。移除也不会引起错误
d。open,close只会在开始与结尾出现一次。
e。separator会使用配置的”,“来每次间隔<foreach>标签内的内容。
f。#{item}中的item必须与<foreach>中的item属性的值”item“保持一致。
------------------------------
4.运行单元测试方法,应该能够看到如下输出:【各位看官可以自行变化数组内容,观察控制台输出】
-------------------------------------------------------------------------------------------------------------------------------------
1.在UserTest中新增单元测试方法:
@Test public void testForEachList() { try { List<String> userlist = new ArrayList<String>(); userlist.add("admin"); userlist.add("customer"); userlist.add("customer2"); UserInfoDao userInfo = sqlSession.getMapper(UserInfoDao.class); List<UserInfo> UIList = userInfo.selectUserInfoByForEachList(userlist); for (UserInfo ui : UIList) { System.out.println(ui.toString()); } } catch (Exception e) { e.printStackTrace(); } }2.在 UserInfoDao.java增加接口内容如下:
List<UserInfo> selectUserInfoByForEachList(List<String> sl);3.在UserInfoDaoMapper.xml中,增加如下内容:
<select id="selectUserInfoByForEachList" resultMap="UserInfoResult"> select * from userinfo <if test="list!=null"> where userid in <foreach item="item" collection="list" index="index" open="(" separator="," close=")"> #{item} </foreach> </if> </select>
【解释】
a.与上面类似:这里的if标签能够判断出List是否为空。但是没有判断出List中的内容是否为空。即,当List中有内容时或者List为null时,该SQL语句能够正常执行,但是如果List为空的话,if判断的结果为真,但foreach执行0次。这种情况下,Mybatis会组装出1条错误的sql语句。换句话说这里if是多余的。
b。这里collection属性配置为”list“
c。index在这条语句中未使用,所以是可以缺省的。移除也不会引起错误
d。其他内容请参考上面array中的解释-------------------------------
4.运行单元测试方法, 应该能够看到如下输出:【各位看官可以自行变化数组内容,观察控制台输出】1.在UserTest中新增单元测试方法:
@Test public void testForEachMap() { try { Map<String, Object> map = new HashMap<String, Object>(); List<String> userlist = new ArrayList<String>(); userlist.add("admin"); map.put("userids", userlist); UserInfoDao userInfo = sqlSession.getMapper(UserInfoDao.class); List<UserInfo> UIList = userInfo.selectUserInfoByForEach(map); for (UserInfo ui : UIList) { System.out.println(ui.toString()); } } catch (Exception e) { e.printStackTrace(); } }2.在 UserInfoDao.java增加接口内容如下:
List<UserInfo> selectUserInfoByForEach(Map<String,Object> map);3.在UserInfoDaoMapper.xml中,增加如下内容:
<select id="selectUserInfoByForEach" parameterType="Map" resultMap="UserInfoResult"> select * from userinfo <if test="userids!=null"> where userid in <foreach item="ParamsId" collection="userids" index="index" open="(" separator="," close=")"> #{ParamsId} </foreach> </if> </select>
【解释】
a.与上面类似:这里的if标签能够判断出map中否包含userids这个key,其对应的value可以任意。但是没有判断出value中的内容是否为空。即,当value中有内容时或者key不存在时,该SQL语句能够正常执行,但是如果value为空的话,if判断的结果为真,但foreach执行0次。这种情况下,Mybatis会组装出1条错误的sql语句。换句话说这里if是多余的。
b.这里collection属性配置为map中list对应的key的值,而不是value或者”list“
c.各位看官请注意这里的#{ParamsId}是与属性item中的ParamsId对应的
----------------------------------
4.运行单元测试方法,应该能够看到如下输出:【各位看官可以自行变化数组内容,观察控制台输出】
-------------------------------------------------------------------------------------------------------------------------------------
四。特别的index
1.在UserTest中新增单元测试方法:
@Test public void testForeachIndex() { try { Map<String, Object> map = new HashMap<String, Object>(); Map<String,Object> user=new HashMap<String, Object>(); user.put("1", "aaa"); user.put("2", "bbb"); user.put("3", "ccc"); user.put("4", "ddd"); user.put("5", "eee"); map.put("map", user); UserDao userDao = sqlSession.getMapper(UserDao.class); int re = userDao.insertUserByForEachIndex(map); if(re==1){ System.out.println("success"); } sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } }2.在 UserDao.java增加接口内容如下:
public interface UserDao { int insertUserByForEachIndex(Map<String,Object> map); }3. 在UserDaoMapper.xml中,增加如下内容:
<insert id="insertUserByForEachIndex"> insert into sysuser (id,password) values <foreach collection="map" index="id" item="item" separator="," open="" close=""> (#{id},#{item}) </foreach> </insert>
【注释】
博主这里找了官方文档,其给出的解释是:当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。当使用字典(或者Map.Entry对象的集合)时,index是键,item是值。
这里我们又参考其他博文中给出的解释,设计上面的示例,供各位看官学习。
作为示例,请读者特别留心SQL语句中所诠释的官方文档的意思。即,index对应key,item对应value。
鉴于篇幅的关系,更多用法就请各位举一反三吧!
----------------------------------
4 .运行单元测试方法, 应该能够看到如下输出:-------------------------------------------------------------------------------------------------------------------------------------
至此,Mybatis最入门---动态查询(foreach)结束
特别备注:
关于<foreach>的用法需要具体应用场景和大量的练习,才能运用自如,请各位客官开心的敲代码吧!
参考资料
官方文档:http://www.mybatis.org/mybatis-3/dynamic-sql.html
其他博文:http://blog.csdn.net/isea533/article/details/21237175