You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron连接本地数据库及Angular5+TypeScript操作SQLite/MySQL问询

嘿,作为Electron+Angular的新手,你碰到的核心问题其实是渲染进程(也就是你的Angular代码)没法直接访问Node.js的数据库模块——这是Electron的安全机制在起作用。不过别慌,我们可以通过「主进程-渲染进程IPC通信」的方式完美解决,下面分SQLite和MySQL两种方案给你一步步讲:

方案一:使用SQLite(轻量本地数据库,适合表单类小体量数据)

SQLite是文件型数据库,不需要单独启动服务,非常适合桌面应用的本地存储需求。

步骤1:安装依赖并处理原生模块

首先在项目根目录安装SQLite相关依赖,因为SQLite是原生模块,需要和Electron的Node版本匹配,所以要执行electron-rebuild:

npm install sqlite3 @types/sqlite3 --save
npx electron-rebuild

步骤2:主进程编写数据库逻辑

在Electron的main.ts中,初始化数据库连接,编写增删改查逻辑,并通过IPC监听渲染进程的请求:

// main.ts
import { app, BrowserWindow, ipcMain } from 'electron';
import * as sqlite3 from 'sqlite3';
import { join } from 'path';

let db: sqlite3.Database;

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // 保持关闭,遵循安全规范
      contextIsolation: true,
      preload: join(__dirname, 'preload.js') // 通过preload桥接IPC通信
    }
  });

  mainWindow.loadURL('http://localhost:4200'); // Angular开发服务器地址
}

app.whenReady().then(() => {
  // 初始化SQLite数据库(存在则打开,不存在则创建)
  db = new sqlite3.Database(join(app.getPath('userData'), 'people.db'), (err) => {
    if (err) console.error('数据库连接失败:', err);
    else {
      // 创建人员表(不存在则创建)
      db.run(`CREATE TABLE IF NOT EXISTS people (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        age INTEGER,
        email TEXT UNIQUE
      )`, (err) => {
        if (err) console.error('创建表失败:', err);
      });
    }
  });

  // 监听渲染进程的「添加人员」请求
  ipcMain.handle('add-person', async (_, personData) => {
    return new Promise((resolve, reject) => {
      db.run(`INSERT INTO people (name, age, email) VALUES (?, ?, ?)`,
        [personData.name, personData.age, personData.email],
        function(err) {
          if (err) reject(err);
          else resolve({ id: this.lastID, success: true });
        }
      );
    });
  });

  // 监听渲染进程的「获取所有人员」请求
  ipcMain.handle('get-all-people', async () => {
    return new Promise((resolve, reject) => {
      db.all(`SELECT * FROM people`, (err, rows) => {
        if (err) reject(err);
        else resolve(rows);
      });
    });
  });

  createWindow();
});

步骤3:编写Preload脚本桥接IPC

因为开启了contextIsolation,渲染进程不能直接调用Electron的ipcRenderer,所以需要在preload脚本中暴露安全的API:

// preload.ts
import { contextBridge, ipcRenderer } from 'electron';

// 向渲染进程暴露安全的数据库操作API
contextBridge.exposeInMainWorld('electronAPI', {
  addPerson: (personData: {name: string, age?: number, email: string}) => 
    ipcRenderer.invoke('add-person', personData),
  getAllPeople: () => ipcRenderer.invoke('get-all-people')
});

记得在项目的tsconfig.json中配置preload脚本的编译规则,确保它能被正确编译为JS文件。

步骤4:Angular组件中调用API

先在src/typings.d.ts中声明全局window的类型,避免TypeScript报错:

declare global {
  interface Window {
    electronAPI: {
      addPerson: (personData: {name: string, age?: number, email: string}) => Promise<{id: number, success: boolean}>,
      getAllPeople: () => Promise<Array<{id: number, name: string, age?: number, email: string}>>
    }
  }
}

export {};

然后在Angular组件中调用API处理表单数据:

// person.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-person',
  templateUrl: './person.component.html'
})
export class PersonComponent implements OnInit {
  people: Array<{id: number, name: string, age?: number, email: string}> = [];
  newPerson = { name: '', age: null, email: '' };

  ngOnInit(): void {
    this.loadPeople();
  }

  async loadPeople() {
    try {
      this.people = await window.electronAPI.getAllPeople();
    } catch (err) {
      console.error('加载人员数据失败:', err);
      // 这里可以给用户显示友好的错误提示
    }
  }

  async addPerson() {
    try {
      await window.electronAPI.addPerson(this.newPerson);
      this.loadPeople();
      // 重置表单
      this.newPerson = { name: '', age: null, email: '' };
    } catch (err) {
      console.error('添加人员失败:', err);
      // 这里可以给用户显示友好的错误提示
    }
  }
}
方案二:使用MySQL(适合需要多设备共享或大数据量的场景)

如果你的数据需要和其他设备共享,或者数据量较大,可以选择MySQL,步骤和SQLite类似,只是主进程的数据库实现不同。

步骤1:安装依赖

MySQL的客户端是纯JS模块,不需要rebuild,直接安装:

npm install mysql2 @types/mysql2 --save

步骤2:主进程编写MySQL逻辑

在main.ts中替换SQLite的初始化和IPC监听代码:

// main.ts 中替换SQLite相关代码
import * as mysql from 'mysql2/promise';

let dbConnection: mysql.Connection;

app.whenReady().then(async () => {
  // 连接MySQL数据库
  try {
    dbConnection = await mysql.createConnection({
      host: 'localhost', // 你的MySQL服务器地址
      user: 'your-username', // 数据库用户名
      password: 'your-password', // 数据库密码
      database: 'your-db-name' // 要使用的数据库名称
    });
    console.log('MySQL连接成功');

    // 确保人员表存在
    await dbConnection.execute(`CREATE TABLE IF NOT EXISTS people (
      id INT AUTO_INCREMENT PRIMARY KEY,
      name VARCHAR(255) NOT NULL,
      age INT,
      email VARCHAR(255) UNIQUE
    )`);
  } catch (err) {
    console.error('MySQL连接失败:', err);
  }

  // 监听添加人员请求
  ipcMain.handle('add-person', async (_, personData) => {
    try {
      const [result] = await dbConnection.execute(
        `INSERT INTO people (name, age, email) VALUES (?, ?, ?)`,
        [personData.name, personData.age, personData.email]
      );
      return { id: (result as any).insertId, success: true };
    } catch (err) {
      throw err;
    }
  });

  // 监听查询所有人员请求
  ipcMain.handle('get-all-people', async () => {
    try {
      const [rows] = await dbConnection.execute(`SELECT * FROM people`);
      return rows;
    } catch (err) {
      throw err;
    }
  });

  createWindow();
});

步骤3-4:复用Preload和Angular代码

Preload脚本和Angular组件的代码和SQLite方案完全一致,因为渲染进程只关心调用的API接口,不关心底层用的是什么数据库。

一些关键注意事项
  • 安全优先:永远不要在渲染进程中处理数据库凭证(比如MySQL的用户名密码),所有数据库操作都放在主进程,渲染进程只负责传递用户输入的数据和接收结果。
  • TypeScript类型:给数据库返回的数据定义明确的类型,避免大量使用any,提高代码的可维护性。
  • 打包注意:打包Electron应用时,SQLite需要确保electron-rebuild执行成功;MySQL则不需要额外处理,因为是纯JS模块。
  • 错误处理:在主进程和渲染进程都要做好错误捕获,给用户显示友好的提示,而不是只在控制台打印错误。

内容的提问来源于stack exchange,提问作者Mohammad Reza Farahani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:52:34