mybatis三种批量插入方式对比

mybatis三种批量插入方式对比【面试+工作】

原创: 奋斗蒙

准备:  

1.表结构

CREATE TABLE `t_user` (   

`id` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '主键', 

`name` varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户名',   

`del_flag` char(1) CHARACTER SET utf8 DEFAULT NULL COMMENT '删除标示',   

PRIMARY KEY (`id`) 

) ENGINE=InnoDB DEFAULT CHARSET=latin1;  

 

2.配置

2.1 jdbc.properties配置

mysql.driver=com.mysql.jdbc.Driver

mysql.url=jdbc:mysql://127.0.0.1:3306/ssm

mysql.username=root

mysql.password=admin

#定义初始连接数

mysql.initialSize=1

#定义最大连接数

mysql.maxActive=20

#定义最大空闲

mysql.maxIdle=20

#定义最小空闲

mysql.minIdle=1

#定义最长等待时间

mysql.maxWait=60000

 

2.2 spring-mybatis.xml配置

<context:component-scan base-package="com.win.ssm"/>

<context:property-placeholder location="classpath:jdbc.properties"/>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

    <property name="driverClassName" value="${mysql.driver}"/>

    <property name="url" value="${mysql.url}"/>

    <property name="username" value="${mysql.username}"/>

    <property name="password" value="${mysql.password}"/>

    <!-- 初始化链接大小-->

    <property name="initialSize" value="${mysql.initialSize}"/>

    <!-- 连接池最大数量-->

    <property name="maxActive" value="${mysql.maxActive}"/>

    <!-- 连接池最大空闲-->

    <property name="maxIdle" value="${mysql.maxIdle}"/>

    <!-- 连接池最小空闲 -->

    <property name="minIdle" value="${mysql.minIdle}"></property>

    <!-- 获取连接最大等待时间-->

    <property name="maxWait" value="${mysql.maxWait}"/>

</bean>

<!-- spring与mybatis整合类 -->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

    <property name="dataSource" ref="dataSource"/>

    <!-- 查找接口的别名 -->

    <property name="typeAliasesPackage" value="com.win"/>

    <!-- 自动扫描mapping.xml文件-->

    <property name="mapperLocations" value="classpath:/mapping/*.xml"/>

</bean>

 

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

    <constructor-arg index="0" ref="sqlSessionFactory" />

    <!--<constructor-arg index="1" value="BATCH" />-->

</bean>

 

<!-- 扫描DAO接口 -->

<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">

    <property name="basePackage" value="com.win.ssm.dao"/>

    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

</bean>

<!-- 事务管理 -->

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

 

第一种:普通for循环插入  

①junit类 

@Test

public void testInsertBatch2() throws Exception {

    long start = System.currentTimeMillis();

    User user;

    SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(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) + "---------------");

}

 

②xml配置 

<insert id="insert">

    INSERT INTO t_user (id, name, del_flag)

          VALUES(#{id}, #{name}, #{delFlag})

</insert>

 

 

第二种:mybatis BATCH模式插入  

①junit类

@Test

public void testInsertBatch2() throws Exception {

    long start = System.currentTimeMillis();

    User user;

    SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);//跟上述sql区别

    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) + "---------------");

}

 

②xml配置与第一种②中使用相同 

 

第三种:foreach方式插入  

①junit类

@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.setId("test" + i);

        user.setName("name" + i);

        user.setDelFlag("0");

        list.add(user);

    }

    userService.insertBatch(list);

    long end = System.currentTimeMillis();

    System.out.println("---------------" + (start - end) + "---------------");

}

 

②xml配置

<insert id="insertBatch">

    INSERT INTO t_user

            (id, name, del_flag)

    VALUES

    <foreach collection ="list" item="user" separator =",">

         (#{user.id}, #{user.name}, #{user.delFlag})

    </foreach >

</insert>


特别注意:mysql默认接受sql的大小是1048576(1M),即第三种方式若数据量超过1M会报如下异常:(可通过调整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. 

 

结果对比:

时间有限测试数据较少,有兴趣可以自己测试以下。(不清楚为什么BATCH有时候比单条循环插入还耗时间,请知道的大神不吝赐教,感谢!)

posted @ 2018-10-08 09:00  叶落无蝉鸣  阅读(63)  评论(0编辑  收藏  举报