上節探討了批量新增數據,這節探討批量更新數據兩種寫法的效率問題。
實現方式有兩種,
一種用for循環通過循環傳過來的參數集合,循環出n條sql,
另一種 用mysql的case when 條件判斷變相的進行批量更新
下面進行實現。
注意第一種方法要想成功,需要在db鏈接url后面帶一個參數 &allowmultiqueries=true
即: jdbc:mysql://localhost:3306/mysqltest?characterencoding=utf-8&allowmultiqueries=true
其實這種東西寫過來寫過去就是差不多一樣的代碼,不做重復的贅述,直接上代碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
<!-- 這次用resultmap接收輸出結果 --> <select id= "findbyname" parametertype= "string" resultmap= "customermap" > select * from t_customer where c_name like concat( '%' , #{name}, '%' ) order by c_cerono limit 0 , 100 </select> <!-- 批量更新第一種方法,通過接收傳進來的參數list進行循環著組裝sql --> <update id= "batchupdate" parametertype= "java.util.map" > <!-- 接收list參數,循環著組裝sql語句,注意 for 循環的寫法 separator= ";" 代表著每次循環完,在sql后面放一個分號 item= "cus" 循環list的每條的結果集 collection= "list" list 即為 map傳過來的參數key --> <foreach collection= "list" separator= ";" item= "cus" > update t_customer set c_name = #{cus.name}, c_age = #{cus.age}, c_sex = #{cus.sex}, c_cerono = #{cus.cerono}, c_cerotype = #{cus.cerotype} where id = #{cus.id} </foreach> </update> <!-- 批量更新第二種方法,通過 case when語句變相的進行批量更新 --> <update id= "batchupdatecasewhen" parametertype= "java.util.map" > update t_customer <trim prefix= "set" suffixoverrides= "," > <!-- 拼接 case when 這是一種寫法 --> <!--<foreach collection= "list" separator= "" item= "cus" open= "c_age = case id" close= "end, " >--> <!--when #{cus.id} then #{cus.age}--> <!--</foreach>--> <!-- 拼接 case when 這是另一種寫法,這種寫著更專業的感覺 --> <trim prefix= "c_name =case" suffix= "end," > <foreach collection= "list" item= "cus" > < if test= "cus.name!=null" > when id=#{cus.id} then #{cus.name} </ if > </foreach> </trim> <trim prefix= "c_age =case" suffix= "end," > <foreach collection= "list" item= "cus" > < if test= "cus.age!=null" > when id=#{cus.id} then #{cus.age} </ if > </foreach> </trim> <trim prefix= "c_sex =case" suffix= "end," > <foreach collection= "list" item= "cus" > < if test= "cus.sex!=null" > when id=#{cus.id} then #{cus.sex} </ if > </foreach> </trim> <trim prefix= "c_cerono =case" suffix= "end," > <foreach collection= "list" item= "cus" > < if test= "cus.cerono!=null" > when id=#{cus.id} then #{cus.cerono} </ if > </foreach> </trim> <trim prefix= "c_cerotype =case" suffix= "end," > <foreach collection= "list" item= "cus" > < if test= "cus.cerotype!=null" > when id=#{cus.id} then #{cus.cerotype} </ if > </foreach> </trim> </trim> <where> <foreach collection= "list" separator= "or" item= "cus" > id = #{cus.id} </foreach> </where> </update> |
接口
1
2
3
4
5
|
list<customer> findbyname(string name); int batchupdate(map<string,object> param); int batchupdatecasewhen(map<string,object> param); |
實現類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
/** * 用于更新時,獲取更新數據 * @param name * @return */ public list<customer> findbyname(string name) { sqlsession sqlsession = null ; try { sqlsession = sqlsessionutil.getsqlsession(); return sqlsession.selectlist( "customer.findbyname" , name); } catch (exception e) { e.printstacktrace(); } finally { sqlsessionutil.closesession(sqlsession); } return new arraylist<customer>(); } /** * 批量更新第一種方式 * @param param * @return */ public int batchupdate(map<string,object> param) { return bathupdate( "customer.batchupdate" ,param); } /** * 批量更新第二種方式 * @param param * @return */ public int batchupdatecasewhen(map<string,object> param) { return bathupdate( "customer.batchupdatecasewhen" ,param); } /** * 公共部分提出 * @param statementid * @param param * @return */ private int bathupdate(string statementid,map param){ sqlsession sqlsession = null ; try { sqlsession = sqlsessionutil.getsqlsession(); int key = sqlsession.update(statementid, param); // commit sqlsession.commit(); return key; } catch (exception e) { sqlsession.rollback(); e.printstacktrace(); } finally { sqlsessionutil.closesession(sqlsession); } return 0 ; } |
測試前準備 首先用上節的 批量插入,插入10000條數據以備下面的批量更新用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@test public void batchinsert() throws exception { map<string,object> param = new hashmap<string,object>(); list<customer> list = new arraylist<customer>(); for ( int i= 0 ;i< 10000 ;i++){ customer customer = new customer(); customer.setname( "準備數據" + i); customer.setage( 15 ); customer.setcerono( "111111111111" +i); customer.setcerotype( 2 ); customer.setsex( 1 ); list.add(customer); } param.put( "list" ,list); long start = system.currenttimemillis(); int result = customerdao.batchinsert(param); system.out.println( "耗時 : " +(system.currenttimemillis() - start)); } |
開始進行測試效率問題。
首先進行的是測試十條數據。調整查詢數據為查詢十條
1
2
3
4
|
<!-- 這次用resultmap接收輸出結果 --> <select id= "findbyname" parametertype= "string" resultmap= "customermap" > select * from t_customer where c_name like concat( '%' , #{name}, '%' ) order by c_cerono limit 0 , 10 </select> |
測試類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@test public void batchudpate() throws exception { map<string,object> param = new hashmap<string,object>(); param.put( "list" ,getfindbyname( "準備數據" , "批量更新01" )); long start = system.currenttimemillis(); customerdao.batchupdate(param); system.out.println( "耗時 : " +(system.currenttimemillis() - start)); } @test public void batchudpatecasewhen() throws exception { map<string,object> param = new hashmap<string,object>(); param.put( "list" ,getfindbyname( "批量更新01" , "準備數據" )); long start = system.currenttimemillis(); customerdao.batchupdatecasewhen(param); system.out.println( "耗時 : " +(system.currenttimemillis() - start)); } private list<customer> getfindbyname(string name, string change){ list<customer> list = customerdao.findbyname(name); system.out.println( "查詢出來的條數 : " + list.size()); if ( null != change && ! "" .equals(change)){ for (customer customer : list){ customer.setname(change); } } return list; } |
第一種拼完整sql的方式耗時:
第二種case when 耗時情況:
結果可以看出,其實case when 耗時比較多。
下面來加大數據量到100條;
第一種拼完整sql的方式耗時:
第二種case when 耗時情況:
結果可以看出,其實case when 耗時仍然比第一種多。
繼續加大數據量到1000條
第一種拼完整sql的方式耗時:
第二種case when 耗時情況:
結果可以看出,其實case when 耗時仍然比第一種多。
繼續加大數據量到10000條
第一種拼完整sql的方式耗時:
第二種case when 耗時情況:
結果可以看出,兩種方式進行批量更新,效率已經不在一個數量級了。case when明顯的慢的多。
看網上有人說第一種的效率跟用代碼循環著一條一條的循環著插入的效率差不多,通過測試我就有疑問了,他是怎么做到的。難道我的代碼有問題?明明第一種的效率很高嘛。
第一種效率其實相當高的,因為它僅僅有一個循環體,只不過最后update語句比較多,量大了就有可能造成sql阻塞。
第二種雖然最后只會有一條更新語句,但是xml中的循環體有點多,每一個case when 都要循環一遍list集合,所以大批量拼sql的時候會比較慢,所以效率問題嚴重。使用的時候建議分批插入。
根據效率,安全方面綜合考慮,選擇適合的很重要。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/xu1916659422/article/details/77971696/