如何在Node.js与SQLite3中按顺序逐行迭代数据?
同步遍历SQLite数据库的解决方案
问题背景
使用db.each()时,异步回调函数不会被内部await,导致所有行的回调会被无间断触发,无法实现处理完当前行再取下一行的同步效果。同时不想使用:
all():会将数十万条记录一次性加载到内存,耗时且占用资源LIMIT x OFFSET y:需要重复执行查询,效率低下
希望实现类似PHP中mysql_fetch_row的逐行同步处理逻辑:
// 每次仅获取一条结果,处理完成后才继续取下一行 while(($row = mysql_fetch_row($queryResult))){ var_dump($row); sleep(123); }
解决方案
方案1:使用异步迭代器(推荐)
利用SQLite3的Statement对象结合ES6异步迭代器,实现逐行同步处理:
const sqlite3 = require('sqlite3').verbose(); const sqlite = require('sqlite'); // 封装异步sleep(避免同步sleep阻塞事件循环) const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); (async () => { const db = await sqlite.open({ filename: './mydatabase.db', driver: sqlite3.Database }); // 获取查询Statement const stmt = await db.prepare('SELECT * FROM mytable'); // 使用异步迭代器逐行处理 for await (const row of stmt) { await sleep(10000); console.log(row); } // 关闭Statement并释放资源 await stmt.finalize(); await db.close(); })();
原理:异步迭代器会等待当前行的处理逻辑(包括await sleep)完成后,才会获取下一行数据,完全符合同步遍历的需求。
方案2:手动封装逐行读取逻辑
通过db.get()方法循环调用,手动控制行的读取时机:
const sqlite3 = require('sqlite3').verbose(); const sqlite = require('sqlite'); const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); (async () => { const db = await sqlite.open({ filename: './mydatabase.db', driver: sqlite3.Database }); // 准备查询语句 const stmt = await db.prepare('SELECT * FROM mytable'); // 定义逐行处理函数 const processRow = async () => { const row = await stmt.get(); if (!row) { // 无更多行,结束处理并释放资源 await stmt.finalize(); await db.close(); return; } // 处理当前行 await sleep(10000); console.log(row); // 递归调用处理下一行 await processRow(); }; // 启动处理流程 await processRow(); })();
原理:每次调用stmt.get()仅获取一行数据,处理完成后再递归调用自身取下一行,实现同步遍历效果。
注意事项
- 避免使用同步版本的
sleep(如require('sleep').sleep),会阻塞整个Node.js事件循环,改用基于setTimeout的异步sleep。 - 处理完成后务必调用
stmt.finalize()关闭Statement,释放数据库资源。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

