前景
在項目開發中往往需要使用到資料的導入和導出,導入就是從Excel中導入到DB中,而導出就是從DB中查詢資料然後使用POI寫到Excel上。
寫本文的背景是因為在工作中遇到了大資料的導入和導出,問題既然來了逃跑不如幹掉它!!!
隻要這一次解決了,後期遇到同樣的問題就好解決了。
廢話不多說,開始撸起來!!!
1 傳統POI的的版本優缺點比較
其實想到資料的導入導出,理所當然的會想到apache的poi技術,以及Excel的版本問題。
既然要做導入導出,那麼我們就先來大緻看一下傳統poi技術的版本以及優缺點對比吧!
首先我們知道POI中我們最熟悉的莫過于WorkBook這樣一個接口,我們的POI版本也在更新的同時對這個幾口的實作類做了更新:
- HSSFWorkbook :
這個實作類是我們早期使用最多的對象,它可以操作Excel2003以前(包含2003)的所有Excel版本。在2003以前Excel的版本字尾還是.xls
- XSSFWorkbook :
這個實作類現在在很多公司都可以發現還在使用,它是操作的Excel2003--Excel2007之間的版本,Excel的擴充名是.xlsx
- SXSSFWorkbook :
這個實作類是POI3.8之後的版本才有的,它可以操作Excel2007以後的所有版本Excel,擴充名是.xlsx
大緻知道了我們在導入導出操作的時候會用到這樣三個實作類以及他們可以操作的Excel版本和字尾之後,我們就要從優缺點分析他們了
HSSFWorkbook
它是POI版本中最常用的方式,不過:
- 它的缺點是 最多隻能導出 65535行,也就是導出的資料函數超過這個資料就會報錯;
- 它的優點是 不會報記憶體溢出。(因為資料量還不到7w是以記憶體一般都夠用,首先你得明确知道這種方式是将資料先讀取到記憶體中,然後再操作)
XSSFWorkbook
- 優點:這種形式的出現是為了突破HSSFWorkbook的65535行局限,是為了針對Excel2007版本的1048576行,16384列,最多可以導出104w條資料;
- 缺點:伴随的問題來了,雖然導出資料行數增加了好多倍,但是随之而來的記憶體溢出問題也成了噩夢。因為你所建立的book,Sheet,row,cell等在寫入到Excel之前,都是存放在記憶體中的(這還沒有算Excel的一些樣式格式等等),可想而知,記憶體不溢出就有點不科學了!!!
SXSSFWorkbook
從POI 3.8版本開始,提供了一種基于XSSF的低記憶體占用的SXSSF方式:
優點:
- 這種方式不會一般不會出現記憶體溢出(它使用了硬碟來換取記憶體空間,
- 也就是當記憶體中資料達到一定程度這些資料會被持久化到硬碟中存儲起來,而記憶體中存的都是最新的資料),
- 并且支援大型Excel檔案的建立(存儲百萬條資料綽綽有餘)。
缺點:
- 既然一部分資料持久化到了硬碟中,且不能被檢視和通路那麼就會導緻,
- 在同一時間點我們隻能通路一定數量的資料,也就是記憶體中存儲的資料;
- sheet.clone()方法将不再支援,還是因為持久化的原因;
- 不再支援對公式的求值,還是因為持久化的原因,在硬碟中的資料沒法讀取到記憶體中進行計算;
- 在使用模闆方式下載下傳資料的時候,不能改動表頭,還是因為持久化的問題,寫到了硬碟裡就不能改變了;
2 使用方式哪種看情況
經過了解也知道了這三種Workbook的優點和缺點,那麼具體使用哪種方式還是需要看情況的:
我一般會根據這樣幾種情況做分析選擇:
1、當我們經常導入導出的資料不超過7w的情況下,可以使用 HSSFWorkbook 或者 XSSFWorkbook都行;
2、當資料量查過7w并且導出的Excel中不牽扯對Excel的樣式,公式,格式等操作的情況下,推薦使用SXSSFWorkbook;
3、當資料量查過7w,并且我們需要操做Excel中的表頭,樣式,公式等,這時候我們可以使用 XSSFWorkbook 配合進行分批查詢,分批寫入Excel的方式來做;
3 百萬資料導入導出(正菜)
鋪墊也做了不少,那麼現在開始講講我在工作中遇到的超百萬資料的導入導出解決方案:
想要解決問題我們首先要明白自己遇到的問題是什麼?
1、 我遇到的資料量超級大,使用傳統的POI方式來完成導入導出很明顯會記憶體溢出,并且效率會非常低;
2、 資料量大直接使用select * from tableName肯定不行,一下子查出來300w條資料肯定會很慢;
3、 300w 資料導出到Excel時肯定不能都寫在一個Sheet中,這樣效率會非常低;估計打開都得幾分鐘;
4、 300w資料導出到Excel中肯定不能一行一行的導出到Excel中。頻繁IO操作絕對不行;
5、 導入時300萬資料存儲到DB如果循環一條條插入也肯定不行;
6、導入時300w資料如果使用Mybatis的批量插入肯定不行,因為Mybatis的批量插入其實就是SQL的循環;一樣很慢。
解決思路:
針對1 :
其實問題所在就是記憶體溢出,我們隻要使用對上面介紹的POI方式即可,主要問題就是原生的POI解決起來相當麻煩。
經過查閱資料翻看到阿裡的一款POI封裝工具EasyExcel,上面問題等到解決;
針對2:
不能一次性查詢出全部資料,我們可以分批進行查詢,隻不過時多查詢幾次的問題,況且市面上分頁插件很多。此問題好解決。
針對3:
可以将300w條資料寫到不同的Sheet中,每一個Sheet寫一百萬即可。
針對4:
不能一行一行的寫入到Excel上,我們可以将分批查詢的資料分批寫入到Excel中。
針對5:
導入到DB時我們可以将Excel中讀取的資料存儲到集合中,到了一定數量,直接批量插入到DB中。
針對6:
不能使用Mybatis的批量插入,我們可以使用JDBC的批量插入,配合事務來完成批量插入到DB。即 Excel讀取分批+JDBC分批插入+事務。
3.1 EasyExcel 簡介
附上GitHub位址:https://github.com/alibaba/easyexcel
GitHub位址上教程和說明很詳細,并且附帶有讀和寫的demo代碼,這裡對它的介紹我就不再詳細說了。
至于EasyExcel底層怎麼實作的這個還有待研究。
3.2 300w資料導出
EasyExcel完成300w資料的導出。技術難點已經知道了,接下來就是針對這一難點提供自己的解決思路即可。
300w資料的導出解決思路:
- 首先在查詢資料庫層面,需要分批進行查詢(我使用的是每次查詢20w)
- 每查詢一次結束,就使用EasyExcel工具将這些資料寫入一次;
- 當一個Sheet寫滿了100w條資料,開始将查詢的資料寫入到另一個Sheet中;
- 如此循環直到資料全部導出到Excel完畢。
注意:
1、我們需要計算Sheet個數,以及循環寫入次數。特别是最後一個Sheet的寫入次數
因為你不知道最後一個Sheet選喲寫入多少資料,可能是100w,也可能是25w因為我們這裡的300w隻是模拟資料,有可能導出的資料比300w多也可能少
2、我們需要計算寫入次數,因為我們使用的分頁查詢,是以需要注意寫入的次數。
其實查詢資料庫多少次就是寫入多少次
//導出邏輯代碼
public void dataExport300w(HttpServletResponse response) {
{
OutputStream outputStream = null;
try {
long startTime = System.currentTimeMillis();
System.out.println("導出開始時間:" + startTime);
outputStream = response.getOutputStream();
ExcelWriter writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX);
String fileName = new String(("excel100w").getBytes(), "UTF-8");
//title
Table table = new Table(1);
List<List<String>> titles = new ArrayList<List<String>>();
titles.add(Arrays.asList("onlineseqid"));
titles.add(Arrays.asList("businessid"));
titles.add(Arrays.asList("becifno"));
titles.add(Arrays.asList("ivisresult"));
titles.add(Arrays.asList("createdby"));
titles.add(Arrays.asList("createddate"));
titles.add(Arrays.asList("updateby"));
titles.add(Arrays.asList("updateddate"));
titles.add(Arrays.asList("risklevel"));
table.setHead(titles);
//模拟統計查詢的資料數量這裡模拟100w
int count = 3000001;
//記錄總數:實際中需要根據查詢條件進行統計即可
Integer totalCount = actResultLogMapper.findActResultLogByCondations(count);
//每一個Sheet存放100w條資料
Integer sheetDataRows = ExcelConstants.PER_SHEET_ROW_COUNT;
//每次寫入的資料量20w
Integer writeDataRows = ExcelConstants.PER_WRITE_ROW_COUNT;
//計算需要的Sheet數量
Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
//計算一般情況下每一個Sheet需要寫入的次數(一般情況不包含最後一個sheet,因為最後一個sheet不确定會寫入多少條資料)
Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
//計算最後一個sheet需要寫入的次數
Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ? oneSheetWriteCount : (totalCount % sheetDataRows % writeDataRows == 0 ? (totalCount / sheetDataRows / writeDataRows) : (totalCount / sheetDataRows / writeDataRows + 1));
//開始分批查詢分次寫入
//注意這次的循環就需要進行嵌套循環了,外層循環是Sheet數目,内層循環是寫入次數
List<List<String>> dataList = new ArrayList<>();
for (int i = 0; i < sheetNum; i++) {
//建立Sheet
Sheet sheet = new Sheet(i, 0);
sheet.setSheetName("測試Sheet1" + i);
//循環寫入次數: j的自增條件是當不是最後一個Sheet的時候寫入次數為正常的每個Sheet寫入的次數,如果是最後一個就需要使用計算的次數lastSheetWriteCount
for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
//集合複用,便于GC清理
dataList.clear();
//分頁查詢一次20w
PageHelper.startPage(j + 1 + oneSheetWriteCount * i, writeDataRows);
List<ActResultLog> reslultList = actResultLogMapper.findByPage100w();
if (!CollectionUtils.isEmpty(reslultList)) {
reslultList.forEach(item -> {
dataList.add(Arrays.asList(item.getOnlineseqid(), item.getBusinessid(), item.getBecifno(), item.getIvisresult(), item.getCreatedby(), Calendar.getInstance().getTime().toString(), item.getUpdateby(), Calendar.getInstance().getTime().toString(), item.getRisklevel()));
});
}
//寫資料
writer.write0(dataList, sheet, table);
}
}
// 下載下傳EXCEL
response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName).getBytes("gb2312"), "ISO-8859-1") + ".xlsx");
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
writer.finish();
outputStream.flush();
//導出時間結束
long endTime = System.currentTimeMillis();
System.out.println("導出結束時間:" + endTime + "ms");
System.out.println("導出所用時間:" + (endTime - startTime) / 1000 + "秒");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
3.2.1 測試機狀态
。。。
3.2.2 使用資料庫版本
資料庫我使用的是Oracle19C在網上查閱其實在資料量不超過1億的情況下,Mysql和Oracle的性能其實相差不大,超過1億,Oracle的各方面優勢才會明顯。
是以這裡可以忽略使用資料庫對時間造成的影響,使用mysql一樣可以完成測試,不需要單獨安裝Oracle。
這次測試在查詢方面我使用的是rownum進行的模拟查詢300w條資料,這種查詢效率其實并不高,實際還有很多優化空間來加快查詢速度,
如:明确查詢具體字段,不要用星号,經常查詢字段增加索引等盡可能提高查詢效率,用時可能會更短。
<select id="findByPage300w" resultType="show.mrkay.pojo.ActResultLog">
select *
from ACT_RESULT_LOG
where rownum <![CDATA[<]]> 3000001
</select>
-- 建表語句:可以參考一下
-- Create table
create table ACT_RESULT_LOG
(
onlineseqid VARCHAR2(32),
businessid VARCHAR2(32),
becifno VARCHAR2(32),
ivisresult VARCHAR2(32),
createdby VARCHAR2(32),
createddate DATE,
updateby VARCHAR2(32),
updateddate DATE,
risklevel VARCHAR2(32)
)
tablespace STUDY_KAY
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
3.2.3 測試結果
下面是300w資料從DB導出到Excel所用時間
從上面結果可以看出,300w的資料導出時間用時2分15秒,并且這是在不适用實體作為映射的情況下,如果使用實體映射不适用循環封裝的話速度會更快(當然這也是在沒有設定表頭等其他表格樣式的情況下)
綜合來說速度還算可以。
在網上查了很多資料有一個部落客測試使用EasyExcel導出102w資料用時105秒,具體可以看一下連結:
https://blog.csdn.net/u014299266/article/details/107790561
看一下導出效果:檔案還是挺大的163M
3.2.4 導出小結
經過測試EasyExcel還是挺快的,并且使用起來相當友善,作者還專門提供了關流方法,不需要我們手動去關流了,也避免了我們經常忘記關流導緻的一系列問題。
導出測試就到這裡,對于資料量小于300W的資料可以使用在一個Sheet中進行導出。這裡就不再示範。
3.3 300w資料導入
代碼不重要首先還是思路
300W資料的導入解決思路
1、首先是分批讀取讀取Excel中的300w資料,這一點EasyExcel有自己的解決方案,我們可以參考Demo即可,隻需要把它分批的參數3000調大即可。我是用的20w;(一會兒代碼一看就能明白)
2、其次就是往DB裡插入,怎麼去插入這20w條資料,當然不能一條一條的循環,應該批量插入這20w條資料,同樣也不能使用Mybatis的批量插入語,因為效率也低。可以參考下面連結【Myabtis批量插入和JDBC批量插入性能對比】
3、使用JDBC+事務的批量操作将資料插入到資料庫。(分批讀取+JDBC分批插入+手動事務控制)
https://www.cnblogs.com/wxw7blog/p/8706797.html
3.3.1 資料庫資料(導入前)
。。。
3.3.2 核心業務代碼
// EasyExcel的讀取Excel資料的API
@Test
public void import2DBFromExcel10wTest() {
String fileName = "D:\\StudyWorkspace\\JavaWorkspace\\java_project_workspace\\idea_projects\\SpringBootProjects\\easyexcel\\exportFile\\excel300w.xlsx";
//記錄開始讀取Excel時間,也是導入程式開始時間
long startReadTime = System.currentTimeMillis();
System.out.println("------開始讀取Excel的Sheet時間(包括導入資料過程):" + startReadTime + "ms------");
//讀取所有Sheet的資料.每次讀完一個Sheet就會調用這個方法
EasyExcel.read(fileName, new EasyExceGeneralDatalListener(actResultLogService2)).doReadAll();
long endReadTime = System.currentTimeMillis();
System.out.println("------結束讀取Excel的Sheet時間(包括導入資料過程):" + endReadTime + "ms------");
}
// 事件監聽
public class EasyExceGeneralDatalListener extends AnalysisEventListener<Map<Integer, String>> {
/**
* 處理業務邏輯的Service,也可以是Mapper
*/
private ActResultLogService2 actResultLogService2;
/**
* 用于存儲讀取的資料
*/
private List<Map<Integer, String>> dataList = new ArrayList<Map<Integer, String>>();
public EasyExceGeneralDatalListener() {
}
public EasyExceGeneralDatalListener(ActResultLogService2 actResultLogService2) {
this.actResultLogService2 = actResultLogService2;
}
@Override
public void invoke(Map<Integer, String> data, AnalysisContext context) {
//資料add進入集合
dataList.add(data);
//size是否為100000條:這裡其實就是分批.當資料等于10w的時候執行一次插入
if (dataList.size() >= ExcelConstants.GENERAL_ONCE_SAVE_TO_DB_ROWS) {
//存入資料庫:資料小于1w條使用Mybatis的批量插入即可;
saveData();
//清理集合便于GC回收
dataList.clear();
}
}
/**
* 儲存資料到DB
*
* @param
* @MethodName: saveData
* @return: void
*/
private void saveData() {
actResultLogService2.import2DBFromExcel10w(dataList);
dataList.clear();
}
/**
* Excel中所有資料解析完畢會調用此方法
*
* @param: context
* @MethodName: doAfterAllAnalysed
* @return: void
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
dataList.clear();
}
}
//JDBC工具類
public class JDBCDruidUtils {
private static DataSource dataSource;
/*
建立資料Properties集合對象加載加載配置檔案
*/
static {
Properties pro = new Properties();
//加載資料庫連接配接池對象
try {
//擷取資料庫連接配接池對象
pro.load(JDBCDruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
擷取連接配接
*/
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
/**
* 關閉conn,和 statement獨對象資源
*
* @param connection
* @param statement
* @MethodName: close
* @return: void
*/
public static void close(Connection connection, Statement statement) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 關閉 conn , statement 和resultset三個對象資源
*
* @param connection
* @param statement
* @param resultSet
* @MethodName: close
* @return: void
*/
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
close(connection, statement);
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/*
擷取連接配接池對象
*/
public static DataSource getDataSource() {
return dataSource;
}
}
# druid.properties配置
driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:ORCL
username=mrkay
password=******
initialSize=10
maxActive=50
maxWait=60000
// Service中具體業務邏輯
/**
* 測試用Excel導入超過10w條資料,經過測試發現,使用Mybatis的批量插入速度非常慢,是以這裡可以使用 資料分批+JDBC分批插入+事務來繼續插入速度會非常快
*
* @param
* @MethodName: import2DBFromExcel10w
* @return: java.util.Map<java.lang.String, java.lang.Object>
*/
@Override
public Map<String, Object> import2DBFromExcel10w(List<Map<Integer, String>> dataList) {
HashMap<String, Object> result = new HashMap<>();
//結果集中資料為0時,結束方法.進行下一次調用
if (dataList.size() == 0) {
result.put("empty", "0000");
return result;
}
//JDBC分批插入+事務操作完成對10w資料的插入
Connection conn = null;
PreparedStatement ps = null;
try {
long startTime = System.currentTimeMillis();
System.out.println(dataList.size() + "條,開始導入到資料庫時間:" + startTime + "ms");
conn = JDBCDruidUtils.getConnection();
//控制事務:預設不送出
conn.setAutoCommit(false);
String sql = "insert into ACT_RESULT_LOG (onlineseqid,businessid,becifno,ivisresult,createdby,createddate,updateby,updateddate,risklevel) values";
sql += "(?,?,?,?,?,?,?,?,?)";
ps = conn.prepareStatement(sql);
//循環結果集:這裡循環不支援"爛布袋"表達式
for (int i = 0; i < dataList.size(); i++) {
Map<Integer, String> item = dataList.get(i);
ps.setString(1, item.get(0));
ps.setString(2, item.get(1));
ps.setString(3, item.get(2));
ps.setString(4, item.get(3));
ps.setString(5, item.get(4));
ps.setTimestamp(6, new Timestamp(System.currentTimeMillis()));
ps.setString(7, item.get(6));
ps.setTimestamp(8, new Timestamp(System.currentTimeMillis()));
ps.setString(9, item.get(8));
//将一組參數添加到此 PreparedStatement 對象的批處理指令中。
ps.addBatch();
}
//執行批處理
ps.executeBatch();
//手動送出事務
conn.commit();
long endTime = System.currentTimeMillis();
System.out.println(dataList.size() + "條,結束導入到資料庫時間:" + endTime + "ms");
System.out.println(dataList.size() + "條,導入用時:" + (endTime - startTime) + "ms");
result.put("success", "1111");
} catch (Exception e) {
result.put("exception", "0000");
e.printStackTrace();
} finally {
//關連接配接
JDBCDruidUtils.close(conn, ps);
}
return result;
}
3.3.3 測試結果
下面是300w資料邊讀邊寫用時間:
大緻計算一下:
從開始讀取到中間分批導入再到程式結束總共用時: (1623127964725-1623127873630)/1000=91.095秒
300w資料正好是分15次插入綜合用時:8209毫秒 也就是 8.209秒
計算可得300w資料讀取時間為:91.095-8.209=82.886秒
結果顯而易見:
EasyExcel分批讀取300W資料隻用了 82.886秒
使用JDBC分批+事務操作插入300w條資料綜合隻用時 8.209秒
------開始讀取Excel的Sheet時間(包括導入資料過程):1623127873630ms------
200000條,開始導入到資料庫時間:1623127880632ms
200000條,結束導入到資料庫時間:1623127881513ms
200000條,導入用時:881ms
200000條,開始導入到資料庫時間:1623127886945ms
200000條,結束導入到資料庫時間:1623127887429ms
200000條,導入用時:484ms
200000條,開始導入到資料庫時間:1623127892894ms
200000條,結束導入到資料庫時間:1623127893397ms
200000條,導入用時:503ms
200000條,開始導入到資料庫時間:1623127898607ms
200000條,結束導入到資料庫時間:1623127899066ms
200000條,導入用時:459ms
200000條,開始導入到資料庫時間:1623127904379ms
200000條,結束導入到資料庫時間:1623127904855ms
200000條,導入用時:476ms
200000條,開始導入到資料庫時間:1623127910495ms
200000條,結束導入到資料庫時間:1623127910939ms
200000條,導入用時:444ms
200000條,開始導入到資料庫時間:1623127916271ms
200000條,結束導入到資料庫時間:1623127916744ms
200000條,導入用時:473ms
200000條,開始導入到資料庫時間:1623127922465ms
200000條,結束導入到資料庫時間:1623127922947ms
200000條,導入用時:482ms
200000條,開始導入到資料庫時間:1623127928260ms
200000條,結束導入到資料庫時間:1623127928727ms
200000條,導入用時:467ms
200000條,開始導入到資料庫時間:1623127934374ms
200000條,結束導入到資料庫時間:1623127934891ms
200000條,導入用時:517ms
200000條,開始導入到資料庫時間:1623127940189ms
200000條,結束導入到資料庫時間:1623127940677ms
200000條,導入用時:488ms
200000條,開始導入到資料庫時間:1623127946402ms
200000條,結束導入到資料庫時間:1623127946925ms
200000條,導入用時:523ms
200000條,開始導入到資料庫時間:1623127952158ms
200000條,結束導入到資料庫時間:1623127952639ms
200000條,導入用時:481ms
200000條,開始導入到資料庫時間:1623127957880ms
200000條,結束導入到資料庫時間:1623127958925ms
200000條,導入用時:1045ms
200000條,開始導入到資料庫時間:1623127964239ms
200000條,結束導入到資料庫時間:1623127964725ms
200000條,導入用時:486ms
------結束讀取Excel的Sheet時間(包括導入資料過程):1623127964725ms------
看一下資料庫的資料是不是真的存進去了300w
可以看到資料比導入前多了300W,測試很成功
圖檔
3.3.4 導入小結
具體我沒有看網上其他人的測試情況,這東西一般也很少有人願意測試,不過這個速度對于我當時解決公司大資料的導入和導出已經足夠,當然公司的業務邏輯很複雜,資料量也比較多,表的字段也比較多,導入和導出的速度會比現在測試的要慢一點,但是也在人類能接受的範圍之内。
4 總結
這次工作中遇到的問題也給我留下了深刻印象,同時也是我職業生涯添彩的一筆。
最起碼履歷上可以寫上你處理過上百萬條資料的導入導出。
最後說一下公司之前怎麼做的,公司之前做法是
限制了使用者的下載下傳數量每次最多隻能有四個人同時下載下傳,并且控制每個使用者最大的導出資料最多隻能是20w,與此同時他們也是使用的JDBC分批導入,但是并沒有手動控制事務。
控制同時下載下傳人數我可以了解,但是控制下載下傳資料最多為20w就顯得有點雞肋了。
這也是我後期要解決的問題。
好了到此結束,相信大神有比我做的更好的,對于EasyExcel内部到底是怎麼實作的還有待考究(有空我再研究研究)。
原文連結:https://mp.weixin.qq.com/s/CbdxHyBV_UaRnXVtt3oD1Q