Logo Vincent
返回文章列表

Electron-开发实践:本地数据库SQLite

Electron
Electron-开发实践:本地数据库SQLite

【前言】

本地存取数据的一些常见的手段:Cookie,LocalStorage,IndexedDB,SQLite等,

这里做下简单的对比

|—存储大小:4k

|—设置有效期:可以

|—服务端获取:可以

|—特点:简单数据存取

LocalStorage

|—存储大小:5M

|—设置有效期:不行

|—服务端获取:不行

|—特点:本地键值对存取

IndexedDB

|—存储大小:250M+

|—设置有效期:不行

|—服务端获取:不行

|—特点:非关系型数据库

SQLite

|—存储大小:无限制

|—设置有效期:不行

|—服务端获取:不行

|—特点:本地关系型数据库

这里推荐两篇文章,分别介绍了LocalStorage和IndexedDB

一篇文章学会LocalStorage

一篇文章学会IndexedDB

【SQLite】

SQLite,著名的本地关系型数据库,官网: https://www.sqlite.org/index.html

SQLite支持各种操作系统使用,包括Linux,Mac,Windows,Android等,下载: https://www.sqlite.org/download.html

同样的也有对应的npm包可以使用,sqlite3: https://www.npmjs.com/package/sqlite3

安装

// install
npm i sqlite3

// m1
npm i sqlite3 --target_arch=arm64

起步

安装好后,按官网的示例跑一下代码,代码如下:

const sqlite3 = require("sqlite3").verbose();
const db = new sqlite3.Database(":memory:");

db.serialize(function () {
  db.run("CREATE TABLE lorem (info TEXT)");

  const stmt = db.prepare("INSERT INTO lorem VALUES (?)");
  for (var i = 0; i < 10; i++) {
    stmt.run("Ipsum " + i);
  }
  stmt.finalize();

  db.each("SELECT rowid AS id, info FROM lorem", function (err, row) {
    console.log(row.id + ": " + row.info);
  });
});

db.close();

以上代码逻辑:

1.创建数据库,这个数据库比较特殊是在内存内的

2.创建表格

3.插入数据

4.查询数据

执行结果如下

文档

SQLIte的文档: https://www.sqlite.org/docs.html

|—支持的数据类型: https://www.sqlite.org/datatype3.html

|—创建表格: https://www.sqlite.org/lang_createtable.html

|—更新表格: https://www.sqlite.org/lang_altertable.html

|—创建视图: https://www.sqlite.org/lang_createview.html

|—删除表格: https://www.sqlite.org/lang_droptable.html

|—插入数据: https://www.sqlite.org/lang_insert.html

|—查询数据: https://www.sqlite.org/lang_select.html

|—删除数据: https://www.sqlite.org/lang_delete.html

npm-sqlite3的文档: https://github.com/TryGhost/node-sqlite3/wiki/API

【qiao-sqlite】

这里为了方便使用,封装了一个npm包: https://code.insistime.com/#/qiao-sqlite

createDB

创建数据库

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./test/test.db");
console.log(db);

createTable

创建表格

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDb("./__tests__/test.db");

// table
const sql =
  "CREATE TABLE if not exists t_project (project_name TEXT, project_appid TEXT, project_icon_url TEXT)";

// test
async function test() {
  try {
    await q.createTable(db, sql);
  } catch (e) {
    console.log(e);
  }
}

// run
test();

showTables

列出表格

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./__tests__/test.db");

// test
async function test() {
  try {
    const rows = await q.showTables(db);
    console.log(rows);
  } catch (e) {
    console.log(e);
  }
}

// run
test();

dropTable

删除表格

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./__tests__/test.db");

// test
async function test() {
  try {
    console.log(await q.showTables(db));
    await q.dropTable(db, "t_project");
    console.log(await q.showTables(db));
  } catch (e) {
    console.log(e);
  }
}

// run
test();

insertData

插入数据

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./__tests__/test.db");

// data
const sql = "insert into t_project values (?, ?, ?)";

// test
async function test() {
  try {
    await q.insertData(db, sql, ["name", "appid", "url"]);
  } catch (e) {
    console.log(e);
  }
}

// run
test();

deleteData

删除数据

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./__tests__/test.db");

// data
const sql = "delete from t_project where rowid=?";

// test
async function test() {
  try {
    await q.deleteData(db, sql, [1]);
  } catch (e) {
    console.log(e);
  }
}

// run
test();

modifyData

修改数据

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./__tests__/test.db");

// data
const sql = "update t_project set project_name=?";

// test
async function test() {
  try {
    await q.modifyData(db, sql, ["name1"]);
  } catch (e) {
    console.log(e);
  }
}

// run
test();

selectData

查询数据

"use strict";

// q
const q = require("qiao-sqlite");

// db
const db = q.createDB("./__tests__/test.db");

// sql
const sql = "SELECT rowid,* FROM t_project";

// test
async function test() {
  try {
    const rows = await q.selectData(db, sql);
    console.log(rows);
  } catch (e) {
    console.log(e);
  }
}

// run
test();

【实践】

SQLite一般应用于大型的Android,iOS应用中,或者桌面应用中,

这里在electron环境下做一下实践,

实践项目的介绍:

一篇文章学会LocalStorage

一篇文章学会Webpack5.x

一篇文章学会lerna

一篇文章学会pm2

一篇文章开发todolist

一篇文章学会IndexedDB

一篇文章学会Electron

这里会在以上基础上,用electron+sqlite3实现一个todo list

主进程封装sqlite方法

electron分为主进程和渲染进程,

sqlite的使用肯定在主进程上,

渲染进程通过ipc通信调用主进程封装好的sqlite方法,

由于需要ipc通信,封装了sqlite相关的方法,如下

"use strict";

// path
const path = require("path");

// electron
const { app } = require("electron");

// sqlite
const {
  createDb,
  createTable,
  dropTable,
  showTables,
  insertData,
  modifyData,
  deleteData,
  selectData,
} = require("qiao-sqlite");

// json
const { success, danger } = require("qiao-json");

/**
 * sqlite
 * @returns
 */
exports.sqlite = () => {
  const userDataPath = app.getPath("userData");
  const dbPath = path.resolve(userDataPath, "./electron.db");
  const db = createDb(dbPath);

  return db;
};

/**
 * dbCreateTable
 * @param {*} sql
 * @returns
 */
exports.dbCreateTable = async (sql) => {
  // check
  if (!sql) return danger("need create table sql");

  // db
  const db = exports.sqlite();

  // create table
  try {
    await createTable(db, sql);
    return success("create table success");
  } catch (e) {
    // return danger('create table fail', e);
    return success("create table success");
  }
};

/**
 * dbDropTable
 * @param {*} tableName
 * @returns
 */
exports.dbDropTable = async (tableName) => {
  // check
  if (!tableName) return danger("need tableName");

  // db
  const db = exports.sqlite();

  // drop table
  try {
    await dropTable(db, tableName);
    return success("drop table success");
  } catch (e) {
    return success("drop table success");
  }
};

/**
 * dbShowTables
 * @returns
 */
exports.dbShowTables = async () => {
  // db
  const db = exports.sqlite();

  // show tables
  try {
    const rows = await showTables(db);
    return success("show table success", rows);
  } catch (e) {
    return success("show table success");
  }
};

/**
 * dbInsertData
 * @param {*} sql
 * @param {*} params
 * @returns
 */
exports.dbInsertData = async (sql, params) => {
  // check
  if (!sql) return danger("need insert data sql");

  // db
  const db = exports.sqlite();

  // insert data
  try {
    await insertData(db, sql, params);
    return success("insert data success");
  } catch (e) {
    return danger("insert data fail", e);
  }
};

/**
 * dbDeleteData
 * @param {*} sql
 * @param {*} params
 * @returns
 */
exports.dbDeleteData = async (sql, params) => {
  // check
  if (!sql) return danger("need delete data sql");

  // db
  const db = exports.sqlite();

  // delete data
  try {
    await deleteData(db, sql, params);
    return success("delete data success");
  } catch (e) {
    return danger("delete data fail", e);
  }
};

/**
 * dbModifyData
 * @param {*} sql
 * @param {*} params
 * @returns
 */
exports.dbModifyData = async (sql, params) => {
  // check
  if (!sql) return danger("need modify data sql");

  // db
  const db = exports.sqlite();

  // modify data
  try {
    await modifyData(db, sql, params);
    return success("modify data success");
  } catch (e) {
    return danger("modify data fail", e);
  }
};

/**
 * dbSelectData
 * @param {*} sql
 * @param {*} params
 * @returns
 */
exports.dbSelectData = async (sql, params) => {
  // check
  if (!sql) return danger("need select data sql");

  // db
  const db = exports.sqlite();

  // select data
  try {
    const rows = await selectData(db, sql, params);
    return success("select data success", rows);
  } catch (e) {
    return danger("select data fail", e);
  }
};

主进程ipc监听

主进程封装好sqlite后,要监听ipc通信,并调用对应的sqlite方法,

如下监听创建表格的方法

"use strict";

// electron
const { ipcMain } = require("electron");

// sqlite
const { dbCreateTable } = require("./sqlite-main.js");

// const
const { IPC_SQLITE_CREATE_TABLE } = require("../../_util/constant.js");

/**
 * ipc sqlite create table
 */
ipcMain.handle(IPC_SQLITE_CREATE_TABLE, (sql) => {
  return dbCreateTable(sql);
});

渲染进程注入preload

渲染进程调用主进程方法,需要先注入preload文件

如下注入了ipc通信的方法

"use strict";

// electron
const { ipcRenderer } = require("electron");

// const
const { IPC_SQLITE_CREATE_TABLE } = require("../../_util/constant.js");

/**
 * createTableIPC
 */
exports.createTableIPC = async () => {
  return await ipcRenderer.invoke(IPC_SQLITE_CREATE_TABLE);
};

渲染进程调用ipc方法

注入preload后,即可在渲染进程,

本项目对应dishi-web文件夹下调用ipc方法,

const sql =
  "CREATE TABLE if not exists t_project (project_name TEXT, project_appid TEXT, project_icon_url TEXT) ";
const rs = await window.electron.createTableIPC(sql);
console.log(rs);

最终效果

1.渲染进程中的js调用ipc方法

2.调用的ipc方式是创建window时注入的preload文件提供

3.主进程监听ipc调用,并执行对应的sqlite方法

如下

完善

按照如上步骤,继续完善基于sqlite的todo list

1.创建数据库和表格

2.新增todo

3.删除todo

4.新增done

5.查询todo

6.查询done

效果如下

以上代码详见: https://github.com/uikoo9/dishi-monorepo/tree/sqlite

【总结】

1.SQLite-介绍Cookie,LocalStorage,IndexedDB和SQLite的不同

2.SQLite-SQLite介绍

3.SQLite-SQLite文档

4.SQLite-sqlite3安装和起步

5.SQLite-sqlite3工具:qiao-sqlite, https://code.insistime.com/#/qiao-sqlite

6.SQLite-另一篇文章: https://uikoo9.blog.csdn.net/article/details/123924787

7.SQLite-实践electron+sqlite项目: https://github.com/uikoo9/dishi-monorepo/tree/sqlite

© 2026 vincentqiao.com . 保留所有权利。