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
繁體地址,請注明出處:http://hk.pswp.cn/web/82446.shtml
英文地址,請注明出處:http://en.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:關鍵參數…