Mybatis执行n条语句

项目用例

1

关于foreach标签,有几个属性应该注意一下:

属性描述

collection	指定要遍历的集合,list类型的参数会特殊处理封装在map中,map的key就叫list
item	将当前遍历出的元素赋值给指定的变量
separator	每个元素之间的分隔符
open	遍历出所有结果拼接一个开始的字符
close	遍历出所有结果拼接一个结束的字符
index	索引。遍历list的时候是index就是索引,item就是当前值。遍历map的时候index表示的就是map的key,item就是map的值, #{变量名}就能取出变量的值也就是当前遍历出的元素。
1
2
3
4
5
6
7
8
9
10
11
12
13

# 一、使用MyBatis对表执行UPDATE批处理——基于XML的实现
## 1、定义mapper接口方法
```java
public interface UserMapper extends BaseDao<UserModel> {

//Mybatis中进行批量更新1
public int updateBatch1(List<User>) throws Exception;

//Mybatis中进行批量更新2
public int updateBatch2(List<User>) throws Exception;

}
## 2、定义sql映射xml文件 以userMapper.xml文件的CUD内容为例,如下:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

<?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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="com.tre.mapper.userMapper"就是com.tre.mapper(包名)+userMapper(userMapper.xml文件去除后缀)
-->
<mapper namespace="com.tre.mapper.userMapper">

<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>

<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.tre.model.SysLog">
<id column="id" property="id" />
<result column="userid" property="userid" />
<result column="username" property="username" />
<result column="years" property="years" />
</resultMap>


<!-- 在select标签中编写查询的SQL语句, 设置select标签的id属性为getUser,id属性值必须是唯一的,不能够重复
使用parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型
resultType="com.tre.model.User"就表示将查询结果封装成一个User类的对象返回
User类就是users表所对应的实体类
-->

<!--更新多条记录为多个字段为不同的值-->
<update id="updateBatch1" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update users
<set>
name=${item.name}
</set>
where id = ${item.id}
</foreach>
</update>


<update id="updateBatch2" parameterType="java.util.List">
update users
set status=
<foreach collection="list" item="item" index="index"
separator=" " open="case ID" close="end">
when #{item.id} then #{item.status}
</foreach>
where id in
<foreach collection="list" index="index" item="item"
separator="," open="(" close=")">
#{item.id,jdbcType=BIGINT}
</foreach>
</update>

</mapper>
# 二、使用MyBatis对表执行INSERT批处理——基于XML的实现 ## 第一种:
1
INSERT INTO table (field1,field2,field3) VALUES ('a',"b","c"), ('a',"b","c"),('a',"b","c")
Mybatis通过foreach循环拼装了如上的sql语句。 ### 1、定义对应的mapper接口
1
public void insertBatch(@Param("emps")List<User> emps);
### 2、定义sql映射xml文件 这里以批量插入数据为例:
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
<?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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="com.tre.mapper.userMapper"就是com.tre.mapper(包名)+userMapper(userMapper.xml文件去除后缀)
-->
<mapper namespace="com.tre.mapper.userMapper">

<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>

<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.tre.model.SysLog">
<id column="id" property="id" />
<result column="userid" property="userid" />
<result column="username" property="username" />
<result column="years" property="years" />
</resultMap>


<insert id="insertBatch" parameterType="java.util.List">
INSERT INTO tb1_emplyee(userid,username,years)
VALUES
<foreach collection="emps" item="emp" separator=",">
(#{emp.userid},#{emp.username},#{emp.years})
</foreach>
</insert>

</mapper>
### 3,junit类测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Resource
private UserMapper userMapper;

@Test
public void testInsertBatch() throws Exception {
long start = System.currentTimeMillis();
List<User> list = new ArrayList<>();
User user;
for (int i = 0; i < 10000; i++) {
user = new User();
user.setUserid("test" + i);
user.setUsername("name" + i);
user.setYears(20);
list.add(user);
}
userMapper.insertBatch(list);
long end = System.currentTimeMillis();
System.out.println("---------------" + (start - end) + "---------------");
}
**特别注意:** mysql默认接受sql的大小是1048576(1M),即第三种方式若数据量超过1M会报如下异常:
1
2
3
4
5
(可通过调整MySQL安装目录下的my.ini文件中[mysqld]段的"max_allowed_packet = 1M")

nested exception is com.mysql.jdbc.PacketTooBigException: Packet for query is too large (5677854 > 1048576).

You can change this value on the server by setting the max_allowed_packet' variable.
## 第二种: mybatis BATCH模式插入 ### 1、定义对应的mapper接口
1
2
3
4
5
6
7
8
9
public void insert(@Param("user")User user);
```java

### 2、定义sql映射xml文件
```xml
<insert id="insert">
INSERT INTO t_user (id, name, del_flag)
VALUES(#{id}, #{name}, #{delFlag})
</insert>
### 3,junit类测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testInsertBatch2() throws Exception {
long start = System.currentTimeMillis();
User user;
SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
UserDao mapper = sqlSession.getMapper(UserDao.class);
for (int i = 0; i < 500; i++) {
user = new User();
user.setId("test" + i);
user.setName("name" + i);
user.setDelFlag("0");
mapper.insert(user);
}
sqlSession.commit();
long end = System.currentTimeMillis();
System.out.println("---------------" + (start - end) + "---------------");
}
## 注意: 第一种方式 我测试了1w条数据的时候差不多需要一秒多时间,可是当我改成10w条的时候,直接ka着不会动了。这种方式是把所有数据拼成一条sql传递给数据库。 第二种方式 在测试1w条的时候虽然看起来比拼接sql慢一点,但在插入10w条的时候不会卡死,差不多就是插入1w条的10倍。数据量较大时推荐使用mybatis提供的ExcecutorType.BATCH。 # 三、使用MyBatis对表执行DELETE批处理——基于XML的实现 当collection=”array“时,表名参数为数组; 当collection=”list“时,表名参数为集合. ## 1、定义对应的mapper接口 public void deleteBatch(int[] arr); ## 2、定义sql映射xml文件 这里以批量插入数据为例:
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
31
32
<?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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="com.tre.mapper.userMapper"就是com.tre.mapper(包名)+userMapper(userMapper.xml文件去除后缀)
-->
<mapper namespace="com.tre.mapper.userMapper">

<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>

<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.tre.model.SysLog">
<id column="id" property="id" />
<result column="userid" property="userid" />
<result column="username" property="username" />
<result column="years" property="years" />
</resultMap>


<!-- 批量删除 -->
<delete id="deleteBatch" parameterType="int[]">
<!-- delete from emp where empno in(7789,7790) -->
<!-- forEach : 用来循环 collection : 用来指定循环的数据的类型 可以填的值有:array,list,map item
: 循环中为每个循环的数据指定一个别名 index : 循环中循环的下标 open : 开始 close : 结束 separator : 数组中元素之间的分隔符 -->
delete from emp where empno in
<foreach collection="array" item="arr" index="no" open="("
separator="," close=")">
#{arr}
</foreach>
</delete>

</mapper>
## 3,junit类测试
1
2
3
4
5
6
7
8
9
10
11
12
@Resource
private UserMapper userMapper;

@Test
public void testInsertBatch() throws Exception {
long start = System.currentTimeMillis();
System.out.println("----------批量删除----------");
int[] arr = { 7791, 7792 };//删除的主键
userMapper.deleteBatch(arr);
long end = System.currentTimeMillis();
System.out.println("---------------" + (start - end) + "---------------");
}