包括,【批量插入】,【批量删除】,【批量更新,待完成…】

目录

一:不使用批处理时,速度很慢,效率低(以插入为例)

(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);
        }
    }
}

运行结果:


五:批处理之:批量更新(待写……)