轉自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 |
通過這種方式提交比較安全不會出現線程鎖表問題,事務處理盡量少,根據每次事務提交執行的量可以實現時間上的優化。