访问数据库
新建数据库 db,数据库中有两张表 Message 和 Chat,截图是 Chat 表的列:
数据库设计好之后,创建一个数据库访问类,由于主进程的逻辑和渲染进程的逻辑都有可能会访问数据库,所以把数据库访问类放置在 src/common 目录下,方便两个进程的逻辑代码使用这个类,代码如下:
src/common/db.ts
import knex, { Knex} from 'knex';
import fs from 'fs';
import path from 'path';
let dbInstance: Knex;
// @ts-ignore
if (!dbInstance) {
let dbPath = process.env.APPDATA || `${process.env.HOME}${process.platform === 'darwin' ? '/Library/Preferences' : '/.local/share'}`;
dbPath = path.join(dbPath, 'Electron');
const dbIsExist = fs.existsSync(dbPath);
if (!dbIsExist) {
console.log(process.execPath)
const resourceDbPath = path.join(process.execPath, '../resources/db.db');
fs.copyFileSync(resourceDbPath, dbPath);
}
dbInstance = knex({
client: 'better-sqlite3',
connection: { filename: dbPath },
useNullAsDefault: true,
})
}
export let db = dbInstance;
导出一个数据库访问对象,只有第一次引入这个数据库访问对象的时候才会执行此对象的初始化逻辑,无论在多少个组件中引入这个数据库访问对象,它只会被初始化一次,但这个约束只局限在一个进程内,也就是说对于整个应用而言,主进程有一个 db 实例,渲染进程也有一个 db 实例,两个实例是完全不同的。
由于渲染进程内的数据库访问对象和主进程内的数据库访问对象不是同一个对象,所以会有并发写入数据的问题,需要控制好你的业务逻辑,避免两个进程在同一时间写入相同的业务数据。
SQLite 不支持并发写入数据,两个或两个以上的写入操作同时执行时,只有一个写操作可以成功执行,其他写操作会失败。并发读取数据没有问题。
第一次初始化数据库链接对象时,会检查 MacintoshHD/用户/[yourOsUserName]/资源库/ApplicationSupport/[yourAppName]/db.db 文件是否存在,如果不存在,就从应用程序安装目录 MacintoshHD/用户/[yourOsUserName]/资源库/ApplicationSupport/[yourAppName]/resources/db.db 拷贝一份到该路径下,所以要提前把数据库设计好,基础数据也要初始化好,制作安装包的时候,把数据库文件打包到安装包里。
通过为 plugins/buildPlugin.ts 增加配置来把数据库文件打包到安装包内的,其中关键的配置代码如下所示:
// buildInstaller 方法内 option.config 的一个属性
extraResources: [{ from: `./src/common/db.db`, to: `./` }]
extraResources 可以让开发者为安装包指定额外的资源文件,electron-builder 打包应用时会把这些资源文件附加到安装包内,当用户安装应用程序时,这些资源会释放在安装目录的 resources/子目录下。
为什么要把数据库文件拷贝再访问,不直接访问安装目录下的数据库文件呢?
因为当用户升级应用程序时安装目录下的文件都会被删除,因为可能会在数据库中放置很多用户数据,这样的话每次升级应用用户这些数据就都没了。
假定数据库是整个应用的核心组件,没有它,数据库应用程序无法正常运行,所以初始化数据库的逻辑都是同步操作(fs.copyFileSync),注意这类以 Sync 结尾的方法都是同步操作,它们是会阻塞 JavaScript 的执行线程的,也就是说在它们执行过程中,其他任何操作都会处于阻塞状态。
在应用程序开发调试阶段,开发者可以先把设计好的数据库文件放置在目标路径 MacintoshHD/用户/[yourOsUserName]/资源库/ApplicationSupport/[yourAppName] 下。
db.ts 文件导出的是一个 Knex 类型的对象,初始化这个对象时,传入一个配置对象,配置对象的 client 属性代表着使用什么模块访问数据库,这里要求 Knex 使用 better-sqlite3 访问数据库,Knex 支持很多数据库,比如 MySql、Oracle、SqlServer 等,都有对应的数据库访问模块。
由于 SQLite 是一个客户端数据库,所以只要把数据库的本地路径告知 Knex 即可,这个属性是通过配置对象的 connection 属性提供的。配置对象的 useNullAsDefault 属性告知 Knex 把开发者未明确提供的数据配置为 Null。
接下来尝试使用这个数据库访问对象把 Chat 表的数据检索出来,代码如下所示:
src/renderer/main.ts
import { db } from "../common/db";
db("Chat")
.first()
.then((obj) => {
console.log(obj);
});
首先创建一个数据库连接对象 db,接着使用这个对象读取 Chat 表里的第一行记录,数据读取成功后把这行数据打印到控制台。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论