Express 集成Sequelize+Sqlite3 默认开启WAL 进程间通信 Conf 打包成可执行 exe 文件

代码:express-exe: 将Express开发的js打包成exe服务丢给客户端使用

实现目标

  1. Express 集成 Sequelize 操作 Sqlite3 数据库;

  2. 启动 Sqlite3 时默认开启 WAL 模式,避免读写互锁,支持并发读;

  3. 利用 Conf 实现主进程与 Express 服务的底层通信;

  4. 打包成可执行文件,在 mac 和 windows 两套系统中均可使用;

Express 集成 Sequelize

  1. Express 在启动时,会检查所有可能的 require 类库,并将该类库实例化,作为单例方式向外导出使用

  2. 这样包括一些类库引入时需要前置构建的工作,即可交给启动函数来执行,执行完毕后,再对外抛出

  3. 遇到异步类函数比较难操作,传统的 commonJS 没有顶层 await,实现等待处理比较麻烦

  4. createModel 函数无需 async/await 化,虽然能保证模型 findAll 之前必然完成 wal 和 sync,但实际操作是主进程以子进程方式先启动 http 服务,之后才开始运行主渲染进程 和 webview 进程,两者产生并发性操作几乎为 0,因此无需耗费心思在每次 User 使用前都等待 db 的统一化操作

  5. Model 只是一种映射类 和 db 链接是两个概念,前者存在的意义是实现 sql 语句拼接的函数化以及返回 sql 的对象化填充时有个 Map 对应,sequelize 才是将 Model 转化的 sql 语句拿去执行的人

    1. 因此,我们可以集中管理 sequelize,封装一个 sequelize 收集类专门收集所有的 db 连接,等服务关闭时,统一关闭 db 链接

以下就是上面实现的具体代码,分为 userModel.js,instanceModel.js,sequelizeCollector.js 三个文件

// userModel.js
// src/models/userModel.js
const { DataTypes } = require('sequelize');
const { createModel } = require('./instanceModel');const { Model, sequelize } = createModel('User', {id: {type: DataTypes.INTEGER,autoIncrement: true,primaryKey: true,},name: {type: DataTypes.STRING,allowNull: false,},email: {type: DataTypes.STRING,allowNull: false,unique: true,},
});module.exports = { User: Model, sequelize };// instanceModel.js
// src/models/instanceModel.js
const sequelizeCollector = require("../db/sequelizeCollector");function createModel(modelName, attributes, options = {}) {// Get Sequelize instance from collectorconst sequelize = sequelizeCollector.getInstance(modelName);// 定义模型const Model = sequelize.define(modelName, attributes, {tableName: modelName.toLowerCase(),freezeTableName: true,timestamps: true,...options,});// 同步模型到数据库(创建表)Model.sync({ force: false }).then(() => {console.log(`${modelName} table synchronized`);}).catch((err) => {console.error(`Failed to sync ${modelName} table:`, err);});return { Model, sequelize };
}module.exports = { createModel };// sequelizeCollector.js
const { Sequelize } = require('sequelize');
const path = require('path');
const ConfigManager = require("../config/ConfManager");class SequelizeCollector {constructor() {this.connections = new Map(); // Using Map to store modelName -> sequelize instancethis.configManager = new ConfigManager({ configName: "starter.http", configPath: "./config" });}// 添加 Sequelize 连接addConnection(modelName, sequelizeInstance) {if (sequelizeInstance && typeof sequelizeInstance.close === 'function') {this.connections.set(modelName, sequelizeInstance);console.log(`Sequelize connection added for model: ${modelName}`);}}// 获取或创建 Sequelize 实例getInstance(modelName) {// Check if instance already existsif (this.connections.has(modelName)) {return this.connections.get(modelName);}// Create new Sequelize instance if it doesn't existconst dbPath = path.join(this.configManager.get("dbPath"), '/sqlite', `${modelName.toLowerCase()}.db`);const sequelize = new Sequelize({dialect: 'sqlite',storage: dbPath,logging: false,});// Enable WAL modesequelize.query('PRAGMA journal_mode = WAL;').then(() => {console.log(`WAL mode enabled for database: ${dbPath}`);}).catch((err) => {console.error(`Failed to enable WAL mode for ${dbPath}:`, err);});// Add to connectionsthis.addConnection(modelName, sequelize);return sequelize;}// 移除 Sequelize 连接removeConnection(modelName) {if (this.connections.has(modelName)) {this.connections.delete(modelName);console.log(`Sequelize connection removed for model: ${modelName}`);}}// 关闭所有 Sequelize 连接async closeAllConnections() {const closePromises = Array.from(this.connections.entries()).map(async ([modelName, sequelize]) => {try {await sequelize.close();this.connections.delete(modelName);console.log(`Sequelize connection closed for model: ${modelName}`);} catch (error) {console.error(`Error closing Sequelize connection for ${modelName}:`, error);}});await Promise.all(closePromises);}// 获取当前连接数量getConnectionCount() {return this.connections.size;}
}// 单例模式
const sequelizeCollector = new SequelizeCollector();module.exports = sequelizeCollector;// userService.js
// services/userService.js
const formatUtils = require('../utils/format'); // 引入工具模块
const {User} = require('../models/userModel');// 获取所有用户
async function getUsers() {try {/*** 下面注释的代码是将 createModel 函数 async/await* 这种方式可保证 wal 和 sync 均完成的后再执行 findAll* 但考虑现实情况, wal 和 sync 操作不需要 await* 因为是单步操作 协程调度下 单步操作基本为交替操作* wal 和 sync 距离很近 操作可在 findAll 前完成* 从输出的 console 也能判断该结论* 此外 因为主渲染进程 和 webview 都在 http 启动之后才开始运行* 所以 wal 和 sync 异步操作没有任何影响* 在协程逻辑下 sync 操作不会和 findAll 同时存在* 因此 sync 理论上会先执行后再执行 findAll*/// const {User, sequelize} = await UserPromise;// console.log(User)const users = await User.findAll();return users.map(user => ({...user.toJSON(),name: formatUtils.capitalize(user.name),email: formatUtils.capitalize(user.email),createdAt: formatUtils.formatDate(user.createdAt),}));} catch (error) {throw new Error(`Error fetching users: ${error.message}`);}
}

打成可执行文件

  1. 利用 windows 的 wsl,运行在 centos 系统中

    1. CentOS7 的类库不支持 node18 版本,会报类库错误

升级为 CentOS8 会遇到以下问题

wsl centos8 二进制安装文件

https://github.com/wsldl-pg/CentWSL/releases

除了将基本镜像更换为腾讯云,还要把下面截图的两个文件里面的镜像更换为腾讯云

curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.cloud.tencent.com/repo/centos8_base.repo
CentOS8 需要额外更改两个文件

解决阿里云CentOS8 yum安装appstream报错,更新yum后无法makecache的问题_errors during downloading metadata for repository -CSDN博客

搞定镜像后,要安装开发包,否则报prebuild-install 错误,这样在pkg . 打包时就不会报prebuild-install错误了

dnf groupinstall -y "Development Tools"
dnf install -y python3 python3-devel
yum install -y python39
echo "alias python3=/usr/bin/python3.9" >> ~/.bashrc
source ~/.bashrc

macos 打包直接双击运行问题

  1. 双击运行默认路径是 /User/xxx 用户根目录,必须到指定路径,使用 ./pkg-express 方式运行,才能正确寻找路径

  2. 因此需要使用绝对路径更好

注意

  1. 切换不同平台时,需要运行 npm rebuild,否则是没有这个平台的二进制的,即使都能打包出来对应的可执行文件,但不可运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/82446.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.Net Framework 4/C# 初识 C#

一、C# 专栏 由于博主原先是做的Linux C/C 嵌入式领域,因此对 C# 也较为懵懂,C# 是典型的 OOP 编程,这一点与 C 类似,但是在语法上,C# 移除了对指针的运用以及内存管理,所以既不用考虑指针的复杂运用也不用…

Python趣学篇:Pygame实现粒子烟花绽放效果

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《Python星球日记》🪐 目录 一、项目亮点与效果预览1. 核心特色功能2. 技术学习价值二、技术原理深度解析1. 向量运算:烟花运动的数学基…

NiceGUI 是一个基于 Python 的现代 Web 应用框架

NiceGUI 是一个基于 Python 的现代 Web 应用框架,它允许开发者直接使用 Python 构建交互式 Web 界面,而无需编写前端代码。以下是 NiceGUI 的主要功能和特点: 核心功能 1.简单易用的 UI 组件 提供按钮、文本框、下拉菜单、滑块、图表等常见…

Linux中的mysql逻辑备份与恢复

一、安装mysql社区服务 二、数据库的介绍 三、备份类型和备份工具 一、安装mysql社区服务 这是小编自己写的,没有安装的去看看 Linux换源以及yum安装nginx和mysql-CSDN博客 二、数据库的介绍 2.1 数据库的组成 数据库是一堆物理文件的集合,主要包括…

鸿蒙UI开发——组件的自适应拉伸

1、概 述 针对常见的开发场景,ArkUI开发框架提供了非常多的自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。本文针对ArkUI提供的拉伸能力做简单讨论。 拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分…

K 值选对,准确率翻倍:KNN 算法调参的黄金法则

目录 一、背景介绍 二、KNN 算法原理 2.1 核心思想 2.2 距离度量方法 2.3 算法流程 2.4算法结构: 三、KNN 算法代码实现 3.1 基于 Scikit-learn 的简单实现 3.2 手动实现 KNN(自定义代码) 四、K 值选择与可视化分析 4.1 K 值对分类…

Azure DevOps Server 2022.2 补丁(Patch 5)

微软Azure DevOps Server的产品组在4月8日发布了2022.2 的第5个补丁。下载路径为:https://aka.ms/devops2022.2patch5 这个补丁的主要功能是修改了代理(Agent)二进制安装文件的下载路径;之前,微软使用这个CND(域名为vstsagentpackage.azuree…

PHP7+MySQL5.6 查立得轻量级公交查询系统

# PHP7MySQL5.6 查立得轻量级公交查询系统 ## 系统简介 本系统是一个基于PHP7和MySQL5.6的轻量级公交查询系统(40KB级),支持线路查询、站点查询和换乘查询功能。系统采用原生PHPMySQL开发,无需第三方框架,适合手机端访问。 首发版本&#x…

Vue-Cropper:全面掌握图片裁剪组件

Vue-Cropper 完全学习指南:Vue图片裁剪组件 🎯 什么是 Vue-Cropper? Vue-Cropper 是一个简单易用的Vue图片裁剪组件,支持Vue2和Vue3。它提供了丰富的配置选项和回调方法,可以满足各种图片裁剪需求。 🌟 …

[Go] Option选项设计模式 — — 编程方式基础入门

[Go] Option选项设计模式 — — 编程方式基础入门 全部代码地址,欢迎⭐️ Github:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-option 1 介绍 在 Go 开发中,我们经常遇到需要处理多参数配置的场景。传统方…

【Unity开发】控制手机移动端的震动

🐾 个人主页 🐾 阿松爱睡觉,横竖醒不来 🏅你可以不屠龙,但不能不磨剑🗡 目录 一、前言二、Unity的Handheld.Vibrate()三、调用Android原生代码四、NiceVibrations插件五、DeviceVibration插件六、控制游戏手…

Linux 软件安装方式全解(适用于 CentOS/RHEL 系统)

🐧 Linux 软件安装方式全解(适用于 CentOS/RHEL 系统) 在 Linux 系统中,软件安装方式丰富多样,常见于以下几种方式: 安装方式命令/工具说明软件包管理器(推荐)yum, dnf, apt, zypp…

前端面试题-HTML篇

1. 请谈谈你对 Web 标准以及 W3C 的理解和认识。 我对 Web 标准 的理解是,它就像是互联网世界的“交通规则”,由 W3C(World Wide Web Consortium,万维网联盟) 这样一个国际性组织制定。这些规则规范了我们在编写 HTML、CSS 和 JavaScript 时应该遵循的语法和行为,比如要…

ERROR: column cl.udt_name does not exist LINE 1 navicat打开金仓表报错

描述: ERROR: column cl.udt_name does not exist LINE 1: …a.columns cl LEFT JOlN pg type ty ON ty.typname cl.udt nam. navicat连上金仓数据库之后,想打开一张表看看,每张表都报这个错,打不开 解决方案: 网上…

2025年- H61-Lc169--74.搜索二维矩阵(二分查找)--Java版

1.题目描述 2.思路 方法一: 定义其实坐标,右上角的元素(0,n-1)。进入while循环(注意边界条件,行数小于m,列数要>0)从右上角开始开始向左遍历(比当…

Jupyter MCP服务器部署实战:AI模型与Python环境无缝集成教程

Jupyter MCP 服务器是基于模型上下文协议(Model Context Protocol, MCP)的 Jupyter 环境扩展组件,它能够实现大型语言模型与实时编码会话的无缝集成。该服务器通过标准化的协议接口,使 AI 模型能够安全地访问和操作 Jupyter 的核心…

MySQL下载安装配置环境变量

MySQL下载安装配置环境变量 文章目录 MySQL下载安装配置环境变量一、安装MySQL1.1 下载1.2 安装 二、查看MySQL服务是否启动三、配置环境变量四、验证 一、安装MySQL 1.1 下载 官网社区版(免费版):https://dev.mysql.com/downloads/mysql/ …

WSL 安装 Debian 12 后,Linux 如何安装 curl , quickjs ?

在 WSL 的 Debian 12 系统中安装 curl 非常简单,你可以直接使用 APT 包管理器从官方仓库安装。以下是详细步骤: 1. 更新软件包索引 首先确保系统的包索引是最新的: sudo apt update2. 安装 curl 执行以下命令安装 curl: sudo…

Linux入门(十四)rpmyum

RPM 是RedHat PackManager的缩写 rpm是用于互联网下载包的打包及安装工具 rpm查询 查询已安装的rpm列表 rpm -qa查看系统是否安装了psmisc rpm -qa | grep psmisc rpm -q psmisc查询软件包信息 rpm -qi psmisc查询软件包中的文件 rpm -ql psmisc根据文件全路径 查询文件所…

[git]忽略.gitignore文件

git rm --cached .gitignore 是一个 Git 命令,主要用于 从版本控制中移除已追踪的 .gitignore 文件,但保留该文件在本地工作目录中。以下是详细解析: 一、命令拆解与核心作用 语法解析 git rm:Git 的删除命令,用于从版本库(Repository)中移除文件。--cached:关键参数…