返回搜索
SQLite 适配器读取数值类型返回 null 的问题
5次浏览1/8/2026
SQLitesql.jsTypeScriptElectrondata-readinggetAsObject

问题描述

在 Electron 应用中使用 sql.js 作为 SQLite 适配器时,性能监控页面的图表数据无法显示。虽然数据已经成功保存到数据库(日志显示保存时数据值正常),但查询时返回的所有数值字段(如 `fps`、`bitrate`、`frameDropRate` 等)都是 `null` 或 `0`。 具体表现: - 数据库查询返回的数据行数正确 - 但所有数值字段的值都是 `null` 或 `0` - 前端图表无法显示数据 - 日志显示数据保存时值正常,但读取时值异常

根本原因

SQLite 适配器在读取数值类型(INTEGER、REAL)时,使用 `getColumn()` 或 `get()` 方法可能返回 `null` 或空值。这是因为: 1. **sql.js API 限制**:`getColumn()` 和 `get()` 方法在处理某些数据类型时可能无法正确读取数值 2. **数据类型转换问题**:SQLite 存储的数值类型在通过 `getColumn()` 读取时可能被错误地转换为 `null` 3. **列名映射问题**:虽然列名正确,但值读取失败 根本原因是 sql.js 的 `getColumn()` 和 `get()` 方法在处理数值类型时存在已知问题,而 `getAsObject()` 方法能够正确处理所有数据类型。

解决方案

修复 `SqlJsStatement.all()` 方法,优先使用 `getAsObject()` 方法读取数据: ```typescript // 在 src/main/utils/database.ts 的 SqlJsStatement.all() 方法中 while (this.stmt.step()) { // 优先使用 getAsObject() 方法,它更可靠且能正确处理所有数据类型 let row: any = null; try { if (typeof this.stmt.getAsObject === 'function') { row = this.stmt.getAsObject(); } } catch (error) { // getAsObject 失败,回退到逐列读取 } // 如果 getAsObject 不可用或失败,使用逐列读取 if (!row || typeof row !== 'object' || Object.keys(row).length === 0) { row = {}; // ... 逐列读取逻辑(作为回退方案) } rows.push(row); } ``` 关键修改点: 1. **优先使用 `getAsObject()`**:在 `step()` 之后立即调用 `getAsObject()` 获取整行数据 2. **回退机制**:如果 `getAsObject()` 不可用或失败,回退到逐列读取方式 3. **类型检查**:确保返回的对象有效且包含数据

背景信息

这是一个基于 Electron + Vue 3 + TypeScript 的推流监控应用。使用 sql.js 作为 SQLite 的内存数据库适配器,通过 `SqlJsAdapter` 封装数据库操作。 技术栈: - **前端**:Vue 3 + TypeScript + Chart.js - **后端**:Electron Main Process + TypeScript - **数据库**:SQLite (通过 sql.js) - **IPC**:Electron IPC 通信 问题发现过程: 1. 前端图表显示为空,但日志显示数据已保存 2. 添加详细日志后发现查询返回的数据字段值都是 `null` 3. 通过调试查询(`SELECT *`)确认数据确实存在于数据库中 4. 检查 `SqlJsStatement.all()` 方法,发现使用 `getColumn()` 读取数据 5. 改为使用 `getAsObject()` 方法后问题解决 相关文件: - `src/main/utils/database.ts` - SQLite 适配器实现 - `src/main/modules/StorageService.ts` - 存储服务,调用数据库查询 - `src/renderer/components/StreamPerformanceViewer.vue` - 前端图表组件