Electron 中使用【SQLite】数据库

1829 字
9 分钟
Electron 中使用【SQLite】数据库

SQLite 介绍#

SQLite 是一个轻量级的数据库系统,通常用于嵌入式系统和桌面应用程序。

创建表#

CREATE TABLE 表名 (

列 1 数据类型,

列 2 数据类型,

列 3 数据类型,

);

create table users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
age INTEGER
);

注:建表的时候确定不了该表是否存在

CREATE TABLE IF NOT EXISTS users;

删除表#

DROP TABLE 表名;

DROP TABLE users;

查询数据中所有表#

SELECT * FROM sqlite_master WHERE type = 'table';

添加列#

ALTER TABLE 表名 ADD COLUMN 列名 数据类型;

ALTER TABLE users ADD COLUMN age INT;

删除列#

ALTER TABLE 表名 DROP COLUMN 列名;

ALTER TABLE users DROP COLUMN age;

插入数据#

INSERT INTO 表名 (列 1, 列 2, 列 3, …) VALUES (值 1, 值 2, 值 3, …);

INSERT INTO users (id, name, age) VALUES (3, 'John3', 325);

注:不是数字的值需要单引号或双引号包括

更新数据#

UPDATE 表名 SET 列 1=值 1, 列 2=值 2, … WHERE 条件;

UPDATE users SET age=26 WHERE id=1;

删除数据#

DELETE FROM 表名 WHERE 条件;

DELETE FROM users WHERE id=1;

查询数据#

  1. 查询所有数据

    SELECT * FROM 表名;

    SELECT * FROM users;
  2. 查询特定列的数据

    SELECT 列名 1, 列名 2 FROM 表名;

    SELECT name, age FROM users;
  3. 查询筛选条件数据

    SELECT * FROM 表名 WHERE 条件;

    SELECT * FROM users WHERE id=1;
  4. 分页查询

    SELECT * FROM 要查询的表名 LIMIT 每页的行数 OFFSET 起始行号;

    SELECT * FROM users LIMIT page_size OFFSET start_row;

SQLite 占位符写法#

db.run("UPDATE tbl SET name = ? WHERE id = ?", "bar", 2);
db.run("UPDATE tbl SET name = ? WHERE id = ?", [ "bar", 2 ]);
db.run("UPDATE tbl SET name = $name WHERE id = $id", { $id: 2, $name: "bar"
});

Electron 中使用 SQLite#

在 Electron 应用中,SQLite 数据库的逻辑通常写在主进程中,而不是渲染进程。

Electron 中为什么要这样使用?#

  1. 安全性

    在 Electron 应用中,主进程和渲染进程通常具有不同的职责和安全性考虑。主进程负责管理应用的生命周期、创建和与数据库进行交互等任务,而渲染进程则负责显示用户界面和处理用户输入。将数据库逻辑放在主进程中可以增加安全性,因为主进程通常具有更严格的权限和访问控制。

  2. 资源管理

    SQLite 数据库的连接和操作需要资源管理。将数据库逻辑放在主进程中可以更好地控制这些资源,避免在渲染进程中产生资源泄漏或竞争条件。

  3. 异步操作

    SQLite 数据库操作通常是异步的,需要回调函数或 Promises 来处理结果。将数据库逻辑放在主进程中可以更好地处理这些异步操作,避免在渲染进程中产生阻塞或延迟。

  4. 简化应用结构

    将数据库逻辑放在主进程中可以简化应用的结构,使代码更易于维护和调试。这样可以确保应用的不同部分(如渲染进程和主进程)能够更好地分离和独立工作。

渲染进程中:通过主进程、渲染进程的 IPC 通信进行调用。

sqlite3 使用步骤#

安装依赖#

Terminal window
npm install sqlite3
# or
yarn install sqlite3

数据库实例以及数据库本地文件#

//  实例
let db
//  数据库表本地文件
const db_path = path.join(app.getAppPath(), '/db-config/sqlite3.db')

连接数据库#

//  连接数据库(electron初始化完成时调用)
db = new sqlite3.Database(db_path, (err) => { //  err错误信息  })

运行 SQL 语句#

run(sql [, param, ...] [, callback]) 参数运行 SQL 查询,然后调用回调

db.run(sql, ...(params || []), (err) => {
//  err 错误信息
//  rows返回值
})

all(sql [, param, ...] [, callback]) 参数运行 SQL 查询,然后调用所有结果行的回调

db.all(sql, ...(params || []), (err, rows) => {
//  err 错误信息
//  rows返回值
})

关闭数据库#

//  关闭数据库(electron应用程序开始关闭窗口时调用)
db && db.close()

electron 使用步骤#

preload 预加载#

ipcRenderer.invoke 主要用于在渲染进程中发送消息给主进程,并接收主进程的返回结果。

它比传统的 ipcRenderer.send 和 ipcMain.on 方式更为方便,因为使用 invoke 可以直接收到主进程返回的信息,而不需要在主进程中再发送一个返回结果。

/** sqlite */
onExecSQL: (params: SqliteType) => {
return IPC_R2M2R.invoke('sqlite:execSQL', params)
}

主进程#

ipcMain.handle 是 Electron 中主进程用来处理渲染进程发送过来的异步或同步消息的方法。这个方法可以接收一个事件和一个回调函数,事件是由渲染进程发送过来的消息,回调函数则是用来处理这个消息的函数。

ipcMain.handle 方法支持异步,触发的方法是 ipcRenderer.invoke

ipcMain.handle('sqlite:execSQL', (e, params) => {
return Promise.resolve(execSQL(params))
})

渲染进程#

window.electronIPC.onExecSQL(data).then((res) => {
//  res返回值
})

完整代码#

import { onSplicingQuotation } from '@/utils'
import { SqlTypeMap } from '@/views/EDB/utils/variable'
/**
* @Author: LGJ
* @Description: 日志
* @Date: 2024/1/2 13:41
*/
}
export const errorger = (strs: any[]) => {
console.error('【error】', ...strs)
}
/**
* @Author: LGJ
* @Description: ERROR记录
* @Date: 2024/1/2 16:04
*/
export const onCheckExecSQLRes = (data: {
fun?: string,
sql: string,
params?: any,
}) => {
return new Promise((resolve, reject) => {
window.electronIPC
.onExecSQL(data)
.then((res: any) => {
const { data, status, message } = res
status === 0 ? resolve(data) : reject(message)
})
.catch((e) => {
errorger([e, data])
})
}).catch((e) => {
errorger([e, data])
})
}
/**
* @Author: LGJ
* @Description: 创建表格
* @Date: 2023/12/29 10:31
*/
export const onCreateTable = (table_name: string) => {
const sql: string =
'CREATE TABLE IF NOT EXISTS ' +
table_name +
' (id INT PRIMARY KEY, company TEXT);'
return onCheckExecSQLRes({ sql })
}
/**
* @Author: LGJ
* @Description: 删除表格
* @Date: 2023/12/29 10:31
*/
export const onDeleteTable = (table_name: string) => {
const sql: string = 'DROP TABLE ' + table_name + ';'
return onCheckExecSQLRes({ sql })
}
/**
* @Author: LGJ
* @Description: 查询数据库有哪些表
* @Date: 2024/1/2 11:24
*/
export const onSelectTable = () => {
const sql: string = "SELECT * FROM sqlite_master WHERE type = 'table';"
return onCheckExecSQLRes({ fun: 'all', sql })
}
/**
* @Author: LGJ
* @Description:
* @Date: 2024/1/9 18:55
*/
export const onSelectTableColumn = (table_name: string) => {
const sql: string = 'PRAGMA table_info(' + table_name + ');'
return onCheckExecSQLRes({ fun: 'all', sql })
}
/**
* @Author: LGJ
* @Description: 添加列,SQLite不支持批量
* @Date: 2023/12/29 10:59
*/
export const onAddTableColumn = (
table_name: string,
column_name: string,
column_type: string
) => {
const sql: string =
'ALTER TABLE ' +
table_name +
' ADD COLUMN ' +
column_name +
' ' +
SqlTypeMap[column_type || 'string'] +
';'
return onCheckExecSQLRes({ sql })
}
/**
* @Author: LGJ
* @Description: 删除列,SQLite不支持批量
* @Date: 2024/1/2 09:48
*/
export const onDeleteTableColumn = (
table_name: string,
column_name: string
) => {
const sql: string =
'ALTER TABLE ' + table_name + ' DROP COLUMN ' + column_name + ';'
return onCheckExecSQLRes({ sql })
}
/**
* @Author: LGJ
* @Description: 添加表格数据
* @Date: 2024/1/2 10:14
*/
export const onAddTableData = (
table_name: string,
table_data: Record<string, any>
) => {
const columns: string[] = Object.keys(table_data)
if (!columns.length) return
const params: string[] = Object.values(table_data)
const values: any = Array(params.length)
.fill(null)
.map((item: any) => '?')
const sql: string =
'INSERT INTO ' +
table_name +
' (' +
columns.join(',') +
') VALUES (' +
values.join(',') +
');'
return onCheckExecSQLRes({ sql, params })
}
/**
* @Author: LGJ
* @Description: 删除表格数据(id)
* @Date: 2024/1/2 10:19
*/
export const onDeleteTableData = (table_name: string, row_id: number) => {
const sql: string =
'DELETE FROM ' +
table_name +
' WHERE id = ' +
onSplicingQuotation(row_id) +
';'
return onCheckExecSQLRes({ sql })
}
/**
* @Author: LGJ
* @Description: 修改表格数据(id)
* @Date: 2024/1/2 14:47
*/
export const onUpdateTableData = (
table_name: string,
row_id: number,
update_data: Record<string, any>
) => {
const columns: string[] = Object.keys(update_data)
if (!columns.length) return
const params: string[] = Object.values(update_data)
const set_sql: string[] = []
columns.forEach((key: string) => {
set_sql.push(key + '= ?')
})
const sql: string =
'UPDATE ' +
table_name +
' SET ' +
set_sql.join(',') +
' WHERE id = ' +
onSplicingQuotation(row_id) +
';'
return onCheckExecSQLRes({ sql, params })
}
/**
* @Author: LGJ
* @Description: 运行指定sql
* @Date: 2024/2/21 11:11
*/
export const onRunAppointSql = (sql: string) => {
return onCheckExecSQLRes({ fun: 'all', sql })
}
Electron 中使用【SQLite】数据库
https://wangxiang.website/posts/前端工程/electron-sqlite3-start/
作者
翔子
发布于
2024-01-06
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
翔子
前端开发工程师
公告
博客已从 VitePress 迁移到 Astro + Firefly 主题,223 篇文章全部保留。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
221
分类
9
标签
28
总字数
411,914
运行时长
0
最后活动
0 天前

文章目录