前文介绍了数据量较小的excel表导入数据库的方法,在数据量较大的情况下就不太适合了,一个是因为mysql命令的执行串长度有限制,二是node-xlsx这个模块加载excel文件是整个文件全部加载到内存,在excel文件较大和可用内存受限的场景就不适合了。我们可以考虑流式读取excel数据,分批次导入数据到数据库。以下是以每批500条记录的示例:
const XLSX = require('xlsx-extract').XLSX;
const mysql = require("mysql2/promise");
const localpool= mysql.createPool({
host:"127.0.0.1",
port:3306,
user:"demouser",
password:"XXXXXX",
database:"demodb",
jsonStrings: true,
waitForConnections: true,
connectionLimit: 4,
enableKeepAlive: true,
keepAliveInitialDelay: 5000,
});
const batchsize=500;
let count=0;
let frist=true;
let batarr=[];
let fieldnames="";
let fieldcounts=0;
new XLSX().extract(process.argv.slice(2)[0], {sheet_id:1})
.on('row', function (row) {
if (frist) { frist=false; fieldcounts=row.length; fieldnames=row.join(); }
else {
for (let j=row.length;j<fieldcounts;j++) row.push("");
batarr.push(row);
if (batarr.length==batchsize) {
let addrecs = "insert into demodb.demotable("+fieldnames+") values ?";
localpool.query(addrecs,[batarr]).then(([results])=>{ console.log(results); batarr=[];}).catch(err=>{console.log(err);});
}
}
})
.on('error', function (err) {
console.error('error', err);
})
.on('end', function (err) {
if (batarr.length>0) {
let addrecs = "insert into demodb.demotable("+fieldnames+") values ?";
localpool.query(addrecs,[batarr]).then(([results])=>{ console.log(results); }).catch(err=>{console.log(err);});
}
});
xlsx-extract这个模块读取行数据时,中间的空白单元会解析成undefined,但是最后一个有值的单元后就截止了,为了和数据库里的字段数保持一致,要将剩余的字段赋值下,示例中赋值为空字符串。
这样可以导入excel大文件进数据库。
其实这样导入数据效率比直接将csv或json文件直接导入mysql效率要低很多,不过有时候转的csv文件或者json文件导入mysql会出现报错情况,需要检查字段值,数据量较大时检查会很麻烦,所以这样导入数据也是不得已的办法。