本文,我们来介绍使用Mybatis提供的标签实现我们某些循环增改删差的需求。官方文档中的内容过于简陋,于是,博主筛选出比较全面讲述foreach用法的的内容,并且配有例子。希望各位看官能够手动敲一遍下面的例子,达到快速学习的目的。
准备工作:
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文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<dependencies>
<dependency>
<groupid>junit</groupid>
junit</artifactid>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.mybatis</groupid>
mybatis</artifactid>
<version>3.3.1</version>
</dependency>
<dependency>
<groupid>mysql</groupid>
mysql-connector-java</artifactid>
<version>5.1.26</version>
</dependency>
<dependency>
<groupid>log4j</groupid>
log4j</artifactid>
<version>1.2.17</version>
</dependency>
</dependencies>
|
3. 数据库 配置文件jdbc.properties内容如下:
1
2
3
4
|
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.
password
=1234
|
1
2
3
4
|
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%n
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<!
--?xml version="1.0" encoding="UTF-8" ?-->
<configuration>
<properties resource=
"jdbc.properties"
>
<settings>
<setting
name
=
"logImpl"
value=
"LOG4J"
>
</setting></settings>
<typealiases>
<package
name
=
"com.csdn.ingo.entity"
>
</package></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}"
>
</property></property></property></property></datasource>
</transactionmanager></environment>
</environments>
<mappers>
<mapper resource=
"mappers/UserInfoMapper.xml"
>
<mapper resource=
"mappers/UserMapper.xml"
>
</mapper></mapper></mappers>
</properties></configuration>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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,请自行补充
}
|
1
2
3
4
5
6
|
@SuppressWarnings(
"serial"
)
public
class
User
implements
Serializable
{
private String id;
private String
password
;
//
set
,get,构造函数,toString,请自行补充
|
1
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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();
}
}
|
准备工作结束,马上开始我们的讲解,请睁大眼见哦!
--------------------------------------------------------------------------------------------------------------------------------
一.参数为数组Array。
1.UserTest的单元测试方法为:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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();
}
}</userinfo>
|
【注意】
2.UserInfoDao.java的内容如下:【注意这里接口的形参为数组类型】
1
2
3
4
5
|
public
interface UserInfoDao {
List<userinfo> selectUserInfoByForEachArray(String[] sa);
}</userinfo>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<!
--?xml version="1.0" encoding="UTF-8" ?-->
<mapper namespace=
"com.csdn.ingo.dao.UserInfoDao"
>
<resultmap id=
"UserInfoResult"
type=
"userInfo"
>
<id
column
=
"userid"
property=
"userid"
>
<result
column
=
"department"
property=
"department"
>
<result
column
=
"position"
property=
"position"
>
<result
column
=
"mobile"
property=
"mobile"
>
<result
column
=
"gender"
property=
"gender"
>
<result
column
=
"email"
property=
"email"
>
</result></result></result></result></result></id></resultmap>
<
select
id=
"selectUserInfoByForEachArray"
resultmap=
"UserInfoResult"
>
select
*
from
userinfo
where
userid
in
#{item}
</
select
>
</mapper>
|
【解释】
a。这里的if标签能够判断出数组是否为空。但是没有判断出数组中的内容是否为空。即,当数组中有内容时或者数组为null时,该SQL语句能够正常执行,但是如果数组为空的话,if判断的结果为真,但foreach执行0次。这种情况下,Mybatis会组装出1条错误的sql语句。换句话说这里if是多余的。
b。这里collection属性配置为”array“
c。index在这条语句中未使用,所以是可以缺省的。移除也不会引起错误
d。open,close只会在开始与结尾出现一次。
e。separator会使用配置的”,“来每次间隔标签内的内容。
f。#{item}中的item必须与中的item属性的值”item“保持一致。
------------------------------
4.运行单元测试方法,应该能够看到如下输出:【各位看官可以自行变化数组内容,观察控制台输出】
-------------------------------------------------------------------------------------------------------------------------------------
二。参数为List
1.在UserTest中新增单元测试方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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();
}
}</userinfo></string></string>
|
1
|
List<userinfo> selectUserInfoByForEachList(List<string> sl);</string></userinfo>
|
1
2
3
4
5
6
7
8
9
|
<
select
id=
"selectUserInfoByForEachList"
resultmap=
"UserInfoResult"
>
select
*
from
userinfo
where
userid
in
#{item}
</
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.运行单元测试方法,应该能够看到如下输出:【各位看官可以自行变化数组内容,观察控制台输出】
-------------------------------------------------------------------------------------------------------------------------------------
三。参数为Map
1.在UserTest中新增单元测试方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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();
}
}</userinfo></string></string></string,></string,>
|
1
|
List<userinfo> selectUserInfoByForEach(Map<string,object> map);</string,object></userinfo>
|
1
2
3
4
5
6
7
8
9
|
<
select
id=
"selectUserInfoByForEach"
parametertype=
"Map"
resultmap=
"UserInfoResult"
>
select
*
from
userinfo
where
userid
in
#{ParamsId}
</
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中新增单元测试方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@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();
}
}</string,></string,object></string,></string,>
|
1
2
3
|
public
interface UserDao {
int
insertUserByForEachIndex(Map<string,object> map);
}</string,object>
|
1
2
3
4
5
6
|
<
insert
id=
"insertUserByForEachIndex"
>
insert
into
sysuser (id,
password
)
values
<foreach
close
=
""
collection=
"map"
index
=
"id"
item=
"item"
open
=
""
separator=
","
>
(#{id},#{item})
</foreach>
</
insert
>
|
【注释】
博主这里找了官方文档,其给出的解释是:当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。当使用字典(或者Map.Entry对象的集合)时,index是键,item是值。
这里我们又参考其他博文中给出的解释,设计上面的示例,供各位看官学习。
作为示例,请读者特别留心SQL语句中所诠释的官方文档的意思。即,index对应key,item对应value。
鉴于篇幅的关系,更多用法就请各位举一反三吧!
----------------------------------
4.运行单元测试方法,应该能够看到如下输出:
-------------------------------------------------------------------------------------------------------------------------------------
至此,Mybatis最入门---动态查询(foreach)结束
特别备注:
关于的用法需要具体应用场景和大量的练习,才能运用自如,请各位客官开心的敲代码吧!
http://www.2cto.com/database/201604/502331.html