1. 程式人生 > >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.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> <!-- springmybatis整合類 --> <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.

結果對比:
第一種 第二種 第三種
500條 7742 7388 622
1000條 15290 15078 746
5000條 78011 177350 1172
10000條 397472 201180 1205
時間有限測試資料較少,有興趣可以自己測試以下。(不清楚為什麼BATCH有時候比單條迴圈插入還耗時間,請知道的大神不吝賜教,感謝!)