一、需求背景
公司爲了對接某數據分析產品A(縮寫是YGFZ),需要將數據庫訂單數據按照A公司格式要求導出到txt文本,然後才能進一步導入到A產品中進行數據分析。
其中要求的格式爲:每行有10個訂單數據,每個數據爲Json字符串格式,也就是每行是一個JsonArray,每個JsonArray有10個元素。
二、分析
目前訂單是千萬級數據庫,每個表10G左右,不可能一次全部查出來,然後在分割成10個10個一組。
那麼,這裏首先根據下單時間查詢,按年份輸出。比如2018年數據,先查出總數據條數,這個速度很快,三百萬數量3秒以內。這三百萬數據也是很龐大,然後分頁查詢,比如每次查詢10萬條,然後把這10萬條組成的ArrayList分割成10個10個小的ArrayList。
// 分割的數組包含fromIndex,不包含toIndex
List<E> subList(int fromIndex, int toIndex);
接下來,先把這些分割好的list放到一個Map中存儲備用。
然後,就開始執行文本輸出操作相關了,新建輸出流
// 根據時間年月日時分秒定義文件名稱
String strDate = DateUtils.formatDate2Str(new Date(), DateUtils.DATE_TIME_PATTON_3);
String fileName = "D:\\" + strDate + ".txt";
File f = new File(fileName);
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
// 如果文件不存在,新建文件
if (!f.exists()) {
f.createNewFile();
}
然後,遍歷剛纔存儲數據的Map,將數據轉爲JsonArray(fastJson)輸出到文件。
// 遍歷map,把每10個訂單數據一行行輸出到文件
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries) {
Object value = entry.getValue();
// 轉爲fast JsonArray
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(value));
logger.info(jsonArray.toString());
bw.write(jsonArray.toString());
// 換行
bw.write("\r\n");
bw.flush();
}
三、測試
在對測試庫3萬多數據進行測試時,生成的文件如下:
不同分頁條數時用時如下:
分頁條數 | 用時(ms) |
---|---|
1000 | 15061 |
5000 | 10228 |
10000 | 9018 |
50000 | 8824 |
由於測試庫一共3萬多條數據,所以分頁5萬10萬沒什麼區別。在數據量大的時候分頁數據越大,則數據連接關閉的次數越少,此間耗時也降低。千萬級數據庫,對內存使用很大,所以在分頁條數也應有所取捨。
四、代碼
public String getOrderDataWriteToTxt(String startTime, String endTime, Integer pageSize) {
String uuid = UUID.randomUUID().toString();
String result = "";
logger.info("getOrderDataWriteToTxt 接收請求:" + uuid + "參數: startTime = " + startTime + ",endTime = " + endTime);
try {
if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
result = ResultUtil.createFailureResult("-10000", "參數有誤!");
return result;
}
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("saleTimeStart", DataUtil.sdcFormatDateStrToPad(startTime, true));
paramMap.put("saleTimeEnd", DataUtil.sdcFormatDateStrToPad(endTime, false));
// 每次從數據庫最多查詢多少條數據
if (pageSize == null) {
pageSize = 1000 * 10;
}
if (pageSize % 10 != 0 || pageSize < 10) {
result = ResultUtil.createFailureResult("-20000", "分頁參數不合理!");
return result;
}
// 查詢在規定時間內數據總條數
int count = orderMapper.selectOrderCountToYiGuan(paramMap);
// 一共能查多少頁
int pageCount = (count % pageSize == 0) ? count / pageSize : (count / pageSize + 1);
// 根據時間年月日時分秒定義文件名稱
String strDate = DateUtils.formatDate2Str(new Date(), DateUtils.DATE_TIME_PATTON_3);
String fileName = "D:\\" + strDate + ".txt";
File f = new File(fileName);
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
// 如果文件不存在,新建文件
if (!f.exists()) {
f.createNewFile();
}
HashMap<String, Object> map = new HashMap<>();
// 分批次查詢數據庫
for (int j = 0; j < pageCount; j++) {
paramMap.put("start", j * pageSize);
paramMap.put("limit", pageSize);
// 查詢訂單數據
List<OrderNew> orderList = orderMapper.selectOrderToYiGuan(paramMap);
// 輸出每行10個
int line = 10;
int size = orderList.size();
// 一共有多少行
int a = (size % line == 0) ? size / line : (size / line + 1);
for (int i = 0; i < a; i++) {
// 將獲取到的訂單列表每十個一組放入map中備用
// subList(int fromIndex, int toIndex) 包含fromIndex,不包含toIndex
map.put("list" + i, orderList.subList(i * line, line * (i + 1) > size ? size : line * (i + 1)));
}
// 遍歷map,把每10個訂單數據一行行輸出到文件
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries) {
Object value = entry.getValue();
// 轉爲fast JsonArray
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(value));
logger.info(jsonArray.toString());
bw.write(jsonArray.toString());
// 換行
bw.write("\r\n");
bw.flush();
}
map.clear();
}
bw.close();
result = ResultUtil.createSuccessResult();
} catch (IOException e) {
e.printStackTrace();
result = ResultUtil.createFailureResult(e);
}
return result;
}
以上代碼所使用的工具類(略)。