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 . 保留所有权利。