Electron 集成 Express + SQlite 解决并发锁库的问题

背景

经过通信层面的优化后,我们不再走 Electron 提供的内置进程间通信 IPC,改为利用 Express 提供的 Http 本地服务来进行多处直达通信机制,同时利用本地 Sqlite 来保存大量数据,但 Express 提供的本地服务是支持并发请求的,而 Sqlite 是不支持行锁的机制,一旦有写入操作,Sqlite 都是直接锁库,除了采用单表单库减少锁库问题外,另外就是走队列的方式来逐个入库,避免写锁问题。

一个Sqlite3教程好文档,分享到这里:函数sqlite3VdbeHalt | SQlite源码分析

解决方案

启用 WAL 模式

WAL 模式即将写的数据暂存在 WAL 文件中,不影响主库,这样就可以避开库锁问题,同时读也可以并行操作,大大提高了 Sqlite 读写并行能力

javascript 复制代码
export const userDataPath = app.getPath('userData')
const storagePath = path.join(userDataPath, '/sqlite/wa_verify.db')

// 创建 Sequelize 实例
export const sequelize = new Sequelize({
    dialect: 'sqlite',
    storage: storagePath,
    define: {
        freezeTableName: true
    },
    logging: false
})

// 启用 WAL 模式
(async () => {
    try {
        await sequelize.authenticate()
        await sequelize.query('PRAGMA journal_mode=WAL;')
        console.log('WAL mode enabled.')
    } catch (error) {
        console.error('Unable to enable WAL mode:', error)
    }
})()

Expess 层面加限流

p-limit 是个好东西,这个直接可控制请求的并发数,如果想搞成队列机制,直接设为 1 即可,省去了自己写队列的烦恼,另外我也第一次发现异步开发的优越性,写个队列也非常简单,而同步开发就没这么方便,必须分为两个进程来搞事情,一个写入队列,一个弹出队列,但是如何保证本地 http 返回结果就很难了,而异步可以一直等待着。

javascript 复制代码
import express from 'express';
import pLimit from 'p-limit';

const app = express();
const port = 3000;

const limit = pLimit(1); // 限制并发请求为 1

app.get('/car', (req, res) => {
    const startTime = Date.now();

    limit(() => new Promise((resolve) => {
        setTimeout(() => {
            const endTime = Date.now();
            const processingTime = endTime - startTime;

            res.json({
                message: '车信息处理完成',
                startTime: new Date(startTime).toISOString(),
                endTime: new Date(endTime).toISOString(),
                processingTime: `${processingTime}ms`
            });

            resolve();
        }, 3000); // 模拟处理时间
    }));
});

app.listen(port, () => {
    console.log(`服务器正在监听 http://localhost:${port}`);
});

客户端测试 Express 并发脚本

javascript 复制代码
import fetch from 'node-fetch';

const url = 'http://localhost:3000/car'; // 你的服务地址
const concurrentRequests = 10; // 请求数

async function sendRequest() {
    const startTime = Date.now();

    try {
        const response = await fetch(url);
        const data = await response.json();
        const endTime = Date.now();

        console.log('响应数据:', data);
        console.log(`请求开始时间: ${data.startTime}`);
        console.log(`请求结束时间: ${data.endTime}`);
        console.log(`处理时间: ${data.processingTime}`);
        console.log(`单个请求的处理时间: ${endTime - startTime}ms`);
    } catch (error) {
        console.error('发生错误:', error);
    }
}

async function testConcurrency() {
    for (let i = 0; i < concurrentRequests; i++) {
        console.log(`发起请求 ${i + 1}...`);
        sendRequest(); // 逐个发送请求,等待每个请求完成
    }
}

testConcurrency();

请求时间结果截图,明显串行执行,完美!

相关推荐
触底反弹14 分钟前
面试被问到 Text2SQL,我用 DeepSeek 自己实现了一个
python·sqlite
susplus1 小时前
【linux应用软件编程】数据库sqlite3
linux·数据库·sqlite
BS30813_vx5 小时前
基于 Express + uni-app 的养老院管理系统设计与实现
后端·uni-app·express
会周易的程序员6 小时前
告别 matiec 与 Docker:aiDgePLC Editor 全面拥抱 STVM 字节码编译
物联网·网关·electron·软plc·iec61131·stvm·open plc
小诗懂技术9 小时前
【sqlite3数据库】一站式学会 增删改查 以及数据库c接口编程
数据库·sqlite
张人玉1 天前
基于 C# WinForms + .NET 8 + SQLite + TCP Socket 的多连接通讯调试工具——TCP通讯助手(TcpAssistant)
tcp/ip·sqlite·c#·.net
Flynt2 天前
Chrome 修了个零日漏洞,你的 VS Code 和 Cursor 可能还在裸奔
安全·electron·visual studio code
__zRainy__2 天前
Node系列 · Express:log4js 日志记录
log4j·express
星辰徐哥2 天前
鸿蒙PC平台 Gnote 笔记应用适配实战:从 Linux 到 鸿蒙PC 的 Electron 迁移
linux·笔记·electron·harmonyos·gnote
一直C2 天前
Linux应用软件编程|嵌入式轻量级数据库SQLite3完整学习笔记(命令行+C语言API)
linux·sqlite