包括,【批量插入】,【批量删除】,【批量更新,待完成…】
目录
一:不使用批处理时,速度很慢,效率低(以插入为例)
(1)Mapper XML中的SQL语句
(2)测试代码:插入一万条数据;
二:批处理之:批量插入;(和一对比一下)
(1)Mapper XML中的SQL语句
(2)测试代码:批量插入一万条数据;
三:批处理的一些问题(以插入为例)
(1)问题1:因为是批量插入数据,无法获取到插入数据的id号:
(2)问题2:批量插入的时候,为了能够满足数据包大小的要求,有时需要采取【分组批量插入的策略】
问题说明:
问题解决案例代码(里面的if嵌套好多,以后改善吧)
四:批处理之:批量删除
(1)Mapper XML中的SQL语句
(2)测试代码:批量删除一万条数据;
五:批处理之:批量更新(待写……)
一:不使用批处理时,速度很慢,效率低(以插入为例)
(1)Mapper XML中的SQL语句
(2)测试代码:插入一万条数据;
/**
* JUnit单元测试类
*/
public class MyBatisTestor {
@Test
public void testInsert1() throws Exception {
SqlSession session = null;
try {
long st = new Date().getTime();
session = MyBatisUtils.openSession();
List list = new ArrayList();
for(int i=0;i<10000;i++){
Goods goods = new Goods();
goods.setTitle("测试商品");
goods.setSubTitle("测试子标题");
goods.setOriginalCost(200f);
goods.setCurrentPrice(100f);
goods.setDiscount(0.5f);
goods.setIsFreeDelivery(1);
goods.setCategoryId(43);
session.insert("goods.insert1", goods);
}
session.commit();
long et = new Date().getTime();
System.out.println("整个插入操作花费时间为:"+(et - st)+"毫秒。");
} catch (Exception e) {
if (session != null) {
session.rollback();
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
}
即上面代码的逻辑是每次只插入一条,一共调用了Mapper XML中的SQL一万次;
运行结果:
二:批处理之:批量插入;(和一对比一下)
利用集合保存数据,然后调用Mapper XML中的SQL语句,把这个集合作为参数传过去,实现批处理。
(1)Mapper XML中的SQL语句
<!--
insert into table(字段1,字段2) values(v1,v2),(v1,v2);
-->
<insert id="batchInsert" parameterType="java.util.List">
insert into t_goods(title,sub_title,original_cost,current_price,discount,is_free_delivery,category_id)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.title},#{item.subTitle},#{item.originalCost},#{item.currentPrice},#{item.discount},#{item.isFreeDelivery},#{item.categoryId})
</foreach>
</insert>
说明:
(1) parameterType设置成List
(2) 插入多条数据,(insert语句的用法可以参考MySQL对数据的基本操作二:INSERT语句(INSERT语句方言,IGNORE关键字,子查询查询整条记录后插入))
(2)测试代码:批量插入一万条数据;
package com.imooc.mybatis;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.imooc.mybatis.dto.GoodsDTO;
import com.imooc.mybatis.entity.Goods;
import com.imooc.mybatis.entity.GoodsDetail;
import com.imooc.mybatis.entity.Student;
import com.imooc.mybatis.utils.MyBatisUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.util.*;
/**
* JUnit单元测试类
*/
public class MyBatisTestor {
@Test
public void testBantchInsert() throws Exception {
SqlSession session = null;
try {
long st = new Date().getTime();
session = MyBatisUtils.openSession();
List list = new ArrayList();
for(int i=0;i<10000;i++){
Goods goods = new Goods();
goods.setTitle("测试商品");
goods.setSubTitle("测试子标题");
goods.setOriginalCost(200f);
goods.setCurrentPrice(100f);
goods.setDiscount(0.5f);
goods.setIsFreeDelivery(1);
goods.setCategoryId(43);
list.add(goods);
}
session.insert("goods.batchInsert", list);
session.commit();
long et = new Date().getTime();
System.out.println("整个插入操作花费时间为:"+(et - st)+"毫秒。");
} catch (Exception e) {
if (session != null) {
session.rollback();
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
}
说明:
(1) 代码的基本逻辑
执行结果:
其中执行的那一条SQL的长长的参数如下:(这个参数有一万条,太长了,这儿只截取了为小部分。)
[main] 15:32:04:873 DEBUG goods.batchInsert - ==> Parameters: 测试商品(String), 测试子标题(String), 200.0(Float), 100.0(Float), 0.5(Float), 1(Integer), 43(Integer), 测试商品(String), 测试子标题(String), 200.0(Float), 100.0(Float), 0.5(Float), 1(Integer), 43(Integer)
可以发现,批量处理花费的时间减少了很多,而且随着数据量的增大,批量处理节省的时间更加明显。
三:批处理的一些问题(以插入为例)
(1)问题1:因为是批量插入数据,无法获取到插入数据的id号:
(2)问题2:批量插入的时候,为了能够满足数据包大小的要求,有时需要采取【分组批量插入的策略】
问题说明:
批量插入的时候,其背后是只执行一条SQL语句,这条SQL语句太长了。比如,上面批量插入10000条数据的时候,执行的那一条SQL的长长的参数如下:(这个参数有一万条,太长了,这儿只截取了为小部分。)
[main] 15:32:04:873 DEBUG goods.batchInsert - ==> Parameters: 测试商品(String), 测试子标题(String), 200.0(Float), 100.0(Float), 0.5(Float), 1(Integer), 43(Integer), 测试商品(String), 测试子标题(String), 200.0(Float), 100.0(Float), 0.5(Float), 1(Integer), 43(Integer)
参数太长,造成最终的这一条SQL语句的大小还是挺大的。如下,这还只是一万条数据,SQL语句中参数的大小就达到了1M了;
又因为服务器操作系统的Linux系统在网络传输信息的时候,对单次传入的信息包的大小是有限制的,如果数据包太大就会被拒绝掉。
具体一次性可以批量插入多少条数据,需要根据insert语句的表结构和SQL的总长度来决定(比如,向一个大表中插入5000条数,其大小就能达到1M;;;而向一个小表中可能插入10万条数据,大小才能达到1M)。。。所以,在批量导入的时候,建议提前做好压力测试,来了解下SQL的执行情况。
问题解决案例代码(里面的if嵌套好多,以后改善吧)
案例演示:比如我们向t_goods表中插入数据的时候,一次最多只能插1000条数据,其解决方案就如下:
/**
* JUnit单元测试类
*/
public class MyBatisTestor {
@Test
public void testBantchInsert() throws Exception {
SqlSession session = null;
try {
long st = new Date().getTime();
session = MyBatisUtils.openSession();
List list = new ArrayList();
for(int i=0;i<967;i++){
Goods goods = new Goods();
goods.setTitle("测试商品");
goods.setSubTitle("测试子标题");
goods.setOriginalCost(200f);
goods.setCurrentPrice(100f);
goods.setDiscount(0.5f);
goods.setIsFreeDelivery(1);
goods.setCategoryId(43);
list.add(goods);
}
// 比如经过压力测试,对于向t_goods表中插入数据,一次插入1000条数据为佳;
if ( list.size()<1000){
session.insert("goods.batchInsert", list);
}else {
for (int i=0;i<=(list.size()/1000 );i++){
if (i !=list.size()/1000){
List<Goods> list1 = list.subList(i * 1000, i * 1000 + 1000);
if (list1.size()!=0){
session.insert("goods.batchInsert", list1);
}
}else {
List<Goods> list1 = list.subList(i * 1000, list.size());
if (list1.size()!=0){
session.insert("goods.batchInsert", list1);
}
}
}
}
session.commit();
long et = new Date().getTime();
System.out.println("整个插入操作花费时间为:"+(et - st)+"毫秒。");
} catch (Exception e) {
if (session != null) {
session.rollback();
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
}
PS:不止插入,向删除或者更新的时候,为了防止数据包过大的情况,也是可以采取同样的思路的。
四:批处理之:批量删除
(1)Mapper XML中的SQL语句
IN子句可以参考:数据库的基本查询三:【WHERE子句】条件查询;这篇博客。
(2)测试代码:批量删除一万条数据;
package com.imooc.mybatis;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.imooc.mybatis.dto.GoodsDTO;
import com.imooc.mybatis.entity.Goods;
import com.imooc.mybatis.entity.GoodsDetail;
import com.imooc.mybatis.entity.Student;
import com.imooc.mybatis.utils.MyBatisUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.util.*;
/**
* JUnit单元测试类
*/
public class MyBatisTestor {
@Test
public void testBatchDelete() throws Exception {
SqlSession session = null;
try {
session = MyBatisUtils.openSession();
List list = new ArrayList();
list.add(1923);
list.add(1924);
list.add(1925);
session.delete("goods.batchDelete", list);
session.commit();
} catch (Exception e) {
if (session != null) {
session.rollback();
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
}
运行结果: