转自http://www.cnblogs.com/fnz0/p/5713102.html
不知道自己什么时候才有这种钻研精神- -。
1 背景
系统中需要批量生成单据数据到数据库表,所以采用批量插入数据库的方式。由于系统中ORM操作集成使用的是Mybatis来完成的。
在Mybatis中操作一般使用批量插入的方式如下:
<insert id="insertBatch" parameterType="java.util.List" >
insert into userinfo (uid, uname, uphone, uaddress)
values
<foreach collection="list" item="item"index="index" separator=",">
(#{item.uid,jdbcType=INTEGER},
#{item.uname,jdbcType=VARCHAR},
#{item.uphone,jdbcType=VARCHAR},
#{item.uaddress,jdbcType=VARCHAR}
)
</foreach>
</insert>
在实际生产中发现,这样调用的效率并不高,于是我们迫切地需要寻找一种处理批量插入性能较高的方式——回归原生数据库JDBC操作。我们要分析Mybatis和JDBC的插入性能,来决策适合我们生产系统的批量插入方式。
参考资料中有一篇文章是对Spring Mybatis和Spring JDBC插入效率的测试,由于测试的数据量不多不予置评。
2 Mybatis
2.1 Mybatis测试样本1K
测试10组数据:
时间(ms) |
923 |
412 |
426 |
408 |
405 |
353 |
365 |
344 |
316 |
493 |
2.2 Mybatis测试样本2K
测试10组数据:
时间(ms) |
11031 |
3340 |
3571 |
2327 |
7273 |
1353 |
2676 |
1249 |
1245 |
1155 |
2.3 Mybatis测试样本4K
测试10组数据:
时间(ms) |
6070 |
5565 |
5731 |
5400 |
5830 |
5543 |
5469 |
5697 |
5528 |
5399 |
2.4 Mybatis测试样本6K
测试10组数据:
时间(ms) |
13383 |
12672 |
13030 |
13484 |
13841 |
12952 |
13331 |
13275 |
13000 |
13236 |
2.5 Mybatis测试样本8K
测试10组数据:
时间(ms) |
25312 |
24702 |
27065 |
25921 |
25156 |
24686 |
25314 |
33947 |
25304 |
25853 |
2.6 Mybatis测试样本10K
测试10组数据:
时间(ms) |
42148 |
39209 |
38548 |
40109 |
37820 |
37728 |
38178 |
38481 |
38157 |
39032 |
2.7 Mybatis测试样本15K
测试10组数据:
时间(ms) |
98250 |
88585 |
87438 |
89547 |
88427 |
89522 |
83261 |
80842 |
87163 |
84804 |
2.8 Mybatis测试样本20K
测试10组数据:
时间(ms) |
145481 |
146618 |
147098 |
145578 |
144947 |
145614 |
142014 |
142315 |
141984 |
143625 |
2.9 性能测试样本平均值
2.9.1 测试样本SQL
2.9.1.1 毫秒级SQL【time(ms)】
-- DELETE FROMprocess_spend_time_result WHEREpmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=1000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=2000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=4000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=6000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=8000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=10000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=15000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=20000 ANDp.pmethod='mybatis';
2.9.1.2 秒级SQL【time(s)】
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=1000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=2000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=4000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=6000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=8000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=10000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=15000 ANDp.pmethod='mybatis';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=20000 ANDp.pmethod='mybatis';
2.9.2 测试数据汇总
数据4舍5入保留3位小数
测试样例 |
AVG(s) |
1K |
0.445 |
2K |
3.522 |
4K |
5.623 |
6K |
13.221 |
8K |
26.326 |
10K |
38.941 |
15K |
87.784 |
20K |
144.527 |
2.10 Mybatis批量插入问题
2.10.1 问题一:处理性能低下
处理10000条耗时:34292ms
2.10.2 问题二:批量处理数据量大小受限
Windows下需要修改MySQL的my.ini文件加入如下配置内容:
max_allowed_packet=500M
Linux下是在/my.cnf修改添加如上内容。
也可以直接这样设置:
SET GLOBAL max_allowed_packet=1073741824;
但MySQL重启后就不起作用了。
2.10.3 问题三:线程处理锁表
在通过多线程并发处理的时,很容易导致数据库表锁表,使得后续的操作无法进行。
2.10.4 问题四:导致对象回收GC问题
对象超出GC对象回收阀值,导致程序中断。
3 JDBC
3.1 JDBC测试数据1W
测试10组数据:
普通插入(ms) |
普通+事务(ms) |
普通批量(ms) |
批量+事务(MS) |
28489 |
801 |
31287 |
3494 |
30536 |
3042 |
35547 |
1899 |
25571 |
2041 |
31022 |
3501 |
27954 |
2733 |
28927 |
2547 |
29620 |
1261 |
34408 |
1449 |
27125 |
819 |
29318 |
923 |
28993 |
1079 |
31099 |
939 |
27594 |
2547 |
33504 |
3410 |
27967 |
781 |
31646 |
3587 |
33145 |
1293 |
37030 |
1912 |
3.2 JDBC测试数据5W
测试10组数据:
普通插入(ms) |
普通+事务(ms) |
普通批量(ms) |
批量+事务(MS) |
131427 |
11568 |
168623 |
6926 |
132271 |
19313 |
231526 |
9915 |
192176 |
5238 |
227724 |
10978 |
185640 |
18955 |
227497 |
41959 |
211777 |
11238 |
184970 |
9461 |
208446 |
5019 |
263636 |
23394 |
253351 |
14265 |
227391 |
24870 |
225268 |
17009 |
229871 |
5583 |
163739 |
9719 |
230719 |
16657 |
215033 |
15802 |
238018 |
5330 |
3.3 JDBC测试数据10W
测试10组数据:
普通插入(ms) |
普通+事务(ms) |
普通批量(ms) |
批量+事务(MS) |
308773 |
21389 |
360510 |
16432 |
352773 |
23487 |
372343 |
25545 |
378805 |
24034 |
368416 |
12507 |
384189 |
30119 |
392974 |
23742 |
369975 |
30651 |
378634 |
26180 |
368659 |
11902 |
416932 |
21321 |
388453 |
12644 |
411571 |
18138 |
391155 |
11287 |
396363 |
11678 |
368055 |
30987 |
399078 |
12212 |
363375 |
22576 |
361478 |
18544 |
3.4 JDBC测试数据25W
测试10组数据:
普通插入(ms) |
普通+事务(ms) |
普通批量(ms) |
批量+事务(MS) |
942067 |
51343 |
990800 |
70103 |
1070688 |
28737 |
1051132 |
35536 |
1002076 |
38065 |
1222409 |
89644 |
1073114 |
57050 |
1312620 |
82354 |
960697 |
51733 |
1338932 |
33428 |
1025890 |
37666 |
1273338 |
76934 |
1017361 |
50916 |
1115627 |
92790 |
1077821 |
78650 |
1175512 |
52427 |
1038000 |
23290 |
1247797 |
91801 |
1200532 |
75494 |
1262051 |
72087 |
3.5 JDBC测试数据50W
测试10组数据:
普通插入(ms) |
普通+事务(ms) |
普通批量(ms) |
批量+事务(MS) |
1914920 |
166575 |
2059826 |
146472 |
2111596 |
62807 |
1897888 |
125075 |
2174029 |
147265 |
1891542 |
166921 |
1948838 |
61284 |
2129791 |
93167 |
1909861 |
167575 |
1856811 |
56286 |
1990816 |
141381 |
1980060 |
148012 |
1896793 |
48087 |
2065937 |
56832 |
2130856 |
174388 |
2019914 |
113289 |
2073636 |
117462 |
2045715 |
102792 |
1966828 |
141319 |
1857867 |
116854 |
3.6 JDBC测试样本均值
3.6.1 测试样本SQL
3.6.1.1 毫秒级SQL【time(ms)】
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime) FROM process_spend_time_resultp WHEREp.plimit=500000andp.pmethod='batchInsert';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime) FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsertWithTransaction2';
3.6.1.2 秒级SQL【time(s)】
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=10000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=50000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime)/1000 FROM process_spend_time_resultp WHEREp.plimit=50000andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=100000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=250000 andp.pmethod='batchInsertWithTransaction2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsert';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsert2';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsertWithTransaction';
SELECTAVG(p.ptime)/1000 FROMprocess_spend_time_result p WHERE p.plimit=500000 andp.pmethod='batchInsertWithTransaction2';
3.6.2 测试数据汇总
测试样例 |
1W(s) |
5W(s) |
10W(s) |
25W(s) |
50W(s) |
普通插入 |
28.70 |
191.91 |
367.42 |
1040.82 |
2011.82 |
普通+事务 |
1.64 |
12.81 |
21.91 |
49.29 |
122.81 |
批量插入 |
32.38 |
223.00 |
385.83 |
1199.02 |
1980.54 |
批量+事务 |
2.37 |
15.51 |
18.63 |
69.71 |
112.57 |
3.7 JDBC测试规律总结
3.7.1 规律一:批量插入尽量使用事务控制
数据4舍5入保留2位小数
测试样例 |
1W(s) |
5W(s) |
10W(s) |
25W(s) |
50W(s) |
普通插入 |
28.70 |
191.91 |
367.42 |
1040.82 |
2011.82 |
普通+事务 |
1.64 |
12.81 |
21.91 |
49.29 |
122.81 |
批量插入 |
32.38 |
223.00 |
385.83 |
1199.02 |
1980.54 |
批量+事务 |
2.37 |
15.51 |
18.63 |
69.71 |
112.57 |
3.7.2 规律二:事务批量处理的数据量不要太大
数据4舍5入保留2位小数
测试样例 |
1W(s) |
5W(s) |
10W(s) |
25W(s) |
50W(s) |
普通插入 |
28.70 |
191.91 |
367.42 |
1040.82 |
2011.82 |
普通+事务 |
1.64 |
12.81 |
21.91 |
49.29 |
122.81 |
批量插入 |
32.38 |
223.00 |
385.83 |
1199.02 |
1980.54 |
批量+事务 |
2.37 |
15.51 |
18.63 |
69.71 |
112.57 |
3.7.3 规律三:适当地设置MySQL参数可以提高数据库性能
数据4舍5入保留2位小数
测试样例 |
1W(s) |
5W(s) |
10W(s) |
25W(s) |
50W(s) |
普通插入 |
28.70 |
191.91 |
367.42 |
1040.82 |
2011.82 |
普通+事务 |
1.64 |
12.81 |
21.91 |
49.29 |
122.81 |
批量插入 |
32.38 |
223.00 |
385.83 |
1199.02 |
1980.54 |
批量+事务 |
2.37 |
15.51 |
18.63 |
69.71 |
112.57 |
3.7.4 规律四:处理数据量和时间不是成倍增长
数据4舍5入保留2位小数
测试样例 |
1W(s) |
5W(s) |
10W(s) |
25W(s) |
50W(s) |
普通插入 |
28.70 |
191.91 |
367.42 |
1040.82 |
2011.82 |
普通+事务 |
1.64 |
12.81 |
21.91 |
49.29 |
122.81 |
批量插入 |
32.38 |
223.00 |
385.83 |
1199.02 |
1980.54 |
批量+事务 |
2.37 |
15.51 |
18.63 |
69.71 |
112.57 |
3.7.5 规律五:数据库性能随数据量的不断加大而降低
数据4舍5入保留2位小数
测试样例 |
1W(s) |
5W(s) |
10W(s) |
25W(s) |
50W(s) |
普通插入 |
28.70 |
191.91 |
367.42 |
1040.82 |
2011.82 |
普通+事务 |
1.64 |
12.81 |
21.91 |
49.29 |
122.81 |
批量插入 |
32.38 |
223.00 |
385.83 |
1199.02 |
1980.54 |
批量+事务 |
2.37 |
15.51 |
18.63 |
69.71 |
112.57 |
4 结论
经过以上测试得出结论:Mybatis的批量适合处理少了数据的批量处理,而JDBC适合大数据量的批量处理。据此,采用JDBC批量+事务处理大数据量的表插入操作是最合适的。
5 方案
因为要考虑JVM的GC所以数据应该限制一下,但鉴于Mybatis大数据量的批量插入效率不高,所以根据数据大小分段治理。
5.1 小于1W使用:Mybatis批量插入方案
对JVM进行调优,但主要的性能瓶颈在批量插入操作。鉴于mybatis在项目开发方面的优势,数据量很小的情况下还是建议使用Mybatis。
5.2 大于1W小于10W使用:JDBC批量+事务处理
对JVM进行调优(设置Stack和GC等)。一般操作30秒以内是可以容忍的性能耗时。
5.3 10W以上数据使用:数据分批+JDBC批量+事务处理
对JVM进行调优(设置Stack和GC等),通过数据分批处理。对于分批处理需要借鉴前面的测试数据来定义分批量的大小,主要是对操作时间调优。
如果是100W、1000W级别的数据量,分批处理可以很大程度地提升插入效率,具体的分批需要通过实践去分配,数据量太大这里就不做实验了。
6 参考资料
JDBC实现往MySQL数据库插入百万数据:http://www.cnblogs.com/fnz0/p/5713102.html
MySQL Max_allowed_packet: http://stackoverflow.com/questions/8062496/how-to-change-max-allowed-packet-size
Spring Mybatis和Spring JDBC的插入效率比较:http://toplchx.iteye.com/blog/1988254
注:另外一种比较高效的导入方式是生成一个文本文件使用MySQL的JDBC LOAD DATA LOCAL INFILE;参考示例:
MySQL使用JDBC LOAD DATA LOCAL INFILE导入注意事项
MySQL使用LOAD DATA LOCAL INFILE数据3-5秒导入40W数据
Java不写文件,LOAD DATA LOCAL INFILE大批量导入数据到MySQL的实现
7.实战演练
注意:事务处理的数据量不能太多。
7.1 JDBC工具类
package com.wlyd.fmcgwms.util.jdbc;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
*JDBC连接工具类
*
*@package com.wlyd.fmcgwms.util.jdbc.JdbcConnection
*@date 2017年4月17日 下午3:32:15
*@author pengjunlin
*@comment
*@update
*/
public class JdbcConnection {
privatestatic Connection conn = null;
private static Properties props = null;
static {
props = new Properties();
try {
props.load(JdbcConnection.class.getResourceAsStream("/jdbc.properties"));
} catch (IOException e1) {
e1.printStackTrace();
}
try {
Class.forName(props.getProperty("jdbc.driverClass"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConn(){
try {
conn = DriverManager.getConnection(props.getProperty("jdbc.jdbcUrl"),props.getProperty("jdbc.user"),props.getProperty("jdbc.password"));
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public void closeConn(){
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
7.2 批量事务插入
7.2.1 接口
/**
* jdbc批量插入
*
* @MethodName: jdbcBatchInsert
* @Description:
* @param user
* @param items
* @return
* @throws Exception
* @throws
*/
int jdbcBatchInsert(EsUser user,List<WmElectronicSheetItem> items) throws Exception;
/**
* jdbc批量插入
*
* @MethodName: jdbcPerBatchInsert
* @Description:
* @param user
* @param items
* @return
* @throws Exception
* @throws
*/
intjdbcPerBatchInsert(EsUser user, List<WmElectronicSheetItem> items) throws Exception;
7.2.2 实现
@Override
publicint jdbcBatchInsert(EsUser user, List<WmElectronicSheetItem> items) throws Exception {
intflag = 0;
intperCount = 100, index = 0;
inttimes = items.size() / perCount;
longstime=System.currentTimeMillis();
try {
do {
// 休眠50ms
Thread.sleep(50);
List<WmElectronicSheetItem>listTemp= null;
if (items.size() >= perCount) {
listTemp = items.subList(0, perCount);// listTemp是分段处理逻辑的参数
}else{
listTemp = items.subList(0, items.size());// listTemp是分段处理逻辑的参数
}
// 遍历当前的值是否正确
Stringresult= "";
for (inti = 0; i < listTemp.size(); i++) {
result += listTemp.get(i) + ",";
}
Log.getLogger(getClass()).info("第" + (index+1)+ "轮:>>" + result);
// 事务单元执行个数==尽量在事务里面处理少一点(事务尽量小一点)
jdbcPerBatchInsert(user, listTemp);
items.removeAll(listTemp);
Log.getLogger(getClass()).info("当前剩余集合长度:>>" + items.size());
index++;
}while(index<= times);
// 计算时间
longetime=System.currentTimeMillis();
Log.getLogger(getClass()).info(">>封装面单号批量事务插入总共耗时-----------------------:"+(etime-stime)+"ms!");
}catch(Exception e) {
e.printStackTrace();
flag=2;
Log.getLogger(getClass()).error("JDBC批量执行插入异常:>>" + items.size());
thrownew RuntimeException();
}
returnflag;
}
@Override
publicintjdbcPerBatchInsert(EsUser user, List<WmElectronicSheetItem> items)
throws Exception {
intflag=0;
Connectionconn=JdbcConnection.getConn();
PreparedStatementpstm= null;
try {
Stringsql= "insert intowm_electronic_sheet_item_? ("
+"WESI_WESB_ID,WESI_CARRIER_CODE,WESI_START_CHARACTER,WESI_SEQUENCE,"
+"WESI_WAREHOUSE_ID, WESI_CODE,WESI_STATE, "
+"CREATOR, CREATE_TIME, MODIFIER,MODIFY_TIME) values"
+"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
conn.setAutoCommit(false);
Log.getLogger(getClass()).info(">>>>>>验证JDBC连接:"+(conn!=null));
for (inti = 0, j = items.size(); i < j; i++) {
WmElectronicSheetItemitem= items.get(i);
pstm = conn.prepareStatement(sql);
pstm.setInt(1, Integer.valueOf(user.getEsCorCode())); // tableName
pstm.setInt(2, item.getWesiWesbId());// WESI_WESB_ID
pstm.setString(3, item.getWesiCarrierCode());// WESI_CARRIER_CODE
pstm.setString(4, item.getWesiStartCharacter());// WESI_START_CHARACTER
pstm.setString(5, item.getWesiSequence());// WESI_SEQUENCE
pstm.setInt(6, item.getWesiWarehouseId());// WESI_WAREHOUSE_ID
pstm.setString(7, item.getWesiCode());// WESI_CODE
pstm.setInt(8, item.getWesiState());// WESI_STATE
pstm.setInt(9, user.getEsId());// CREATOR
pstm.setTimestamp(10,new java.sql.Timestamp(new Date().getTime()));// CREATE_TIME
pstm.setInt(11, -1);// MODIFIER
pstm.setTimestamp(12, null);// MODIFY_TIME
pstm.executeUpdate();
}
conn.commit();// 手动提交事务
}catch(Exception e) {
e.printStackTrace();
flag=2;
Log.getLogger(getClass()).error("JDBC批量分配事务单元执行插入异常:>>" + items.size());
thrownew RuntimeException();
}finally{
if (pstm != null) {
try {
pstm.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
conn.close();
}
}
returnflag;
}
7.3测试一组数据
测试50000条数据耗时统计:
数据样本事务大小 (每个事务处理的数量) |
耗时(ms) |
100 |
100258 |
500 |
75041 |
1000 |
68850 |
3000 |
78354 |
通过这种方式提交比较安全不会出现线程锁表问题,事务处理尽量少,根据每次事务提交执行的量可以实现时间上的优化。