前言:項目開發中沒有考慮到數據量的問題,在運行階段突然有一天報Packet for query is too large錯誤。這裡先說個例子,比如有10條數據需要插入到資料庫。我們通常的實現是:
List<Object> list = new ArrayList<>();
for(int i=0;i<list .size());i++){
insert(list.get(i)))
}
// sql語句就是10個insert into table values(?,?)
而我不想在循環list了,我想一條sql搞定,因為mysql不是可以insert into table values(?,?),(?,?),(?,?)這樣寫嗎。我在mybatis中使用foreach就可以實現了。
List<Object> list = new ArrayList<>();
Map<String,Object> map = new HashMap<String,Object>();
map.put("list",list);
insert(map);
如下mybatis中foreach的寫法,collection中的list就是我map中的list。
foreach寫法
但是這裡有個bug,我沒有考慮到mysql中有一個大小限制,即max_allowed_packet。
項目這是運行後,發現有一個大帳戶,插入一直報錯,查看日誌發現如圖錯誤。
報錯信息
Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large
意思就是我超過Packet的最大限制了。也就是我上面提到的max_allowed_packet這個參數。查看這個參數:
查看max_allowed_packet
1048576位元組=1M,也就是mysql默認的。那麼問題來了,我是修改這個參數,還是另尋其它解決辦法。我選擇了最後一個。原因:
因為線上資料庫不允許重啟,網上百度說設置這個參數後,重啟才能生效。
這個值設置多大合適不知道,我這次設置為2M,下次可能出現個3M的情況。
不知道大家有沒有實現過採用文件的形式插入數據,即load方式。
我的實現方式,先把數據寫入到csv文件裡,我通過load把這個文件的數據插入到資料庫。
load方式
這裡呢一定要注意編碼問題,不然會亂碼還有數據之間是採用什麼分隔的,如csv就是使用「,」分隔。
csv文件導入的sql:
LOAD DATA LOCAL INFILE 'E:/1111.csv' ignore into table qwe1231 CHARACTER SET utf8
fields terminated by ',' enclosed by "" IGNORE 1 LINES
總結:
在查詢大數據量和插入大數據量數據時,一定要注意max_allowed_packet的值問題,這裡我們可以採用分頁查詢,分頁插入。
load方式在處理大數據量問題還是比較容易的,而且速度很快。
來源:
https://www.toutiao.com/i6779085316209771019/
「IT大咖說」歡迎廣大技術人員投稿,投稿郵箱:aliang@itdks.com
IT大咖說 | 關於版權
由「IT大咖說(ID:itdakashuo)」原創的文章,轉載時請註明作者、出處及微信公眾號。投稿、約稿、轉載請加微信:ITDKS10(備註:投稿),茉莉小姐姐會及時與您聯繫!
感謝您對IT大咖說的熱心支持!