mybatis的三种批量插入以及次效率比较
正文前先来一波福利推荐:
福利一:
百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的 VIP 课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。
福利二:
毕业答辩以及工作上各种答辩,平时积累了不少精品 PPT,现在共享给大家,大大小小加起来有几千套,总有适合你的一款,很多是网上是下载不到。
获取方式:
微信关注 精品 3 分钟 ,id 为 jingpin3mins,关注后回复 百万年薪架构师 ,精品收藏 PPT 获取云盘链接,谢谢大家支持!
----------------------- 正文开始 ---------------------------
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> <!-- 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.
结果对比:
第一种 | 第二种 | 第三种 | |
500 条 | 7742 | 7388 | 622 |
1000 条 | 15290 | 15078 | 746 |
5000 条 | 78011 | 177350 | 1172 |
10000 条 | 397472 | 201180 | 1205 |