数据库集成 #

一、数据库选择 #

1.1 数据库对比 #

数据库 类型 适用场景 特点
SQLite 关系型 结构化数据 轻量、无服务、SQL支持
LevelDB 键值对 简单存储 高性能、嵌入式
NeDB 文档型 小型应用 纯JS、类MongoDB
PouchDB 文档型 离线应用 同步支持

1.2 选择建议 #

text
- 简单键值存储 → electron-store / LevelDB
- 结构化数据 → SQLite
- 文档型数据 → NeDB / PouchDB
- 需要同步 → PouchDB

二、SQLite #

2.1 安装 #

bash
npm install better-sqlite3
# 或
npm install sqlite3

2.2 基本使用 #

javascript
const Database = require('better-sqlite3');
const path = require('path');
const { app } = require('electron');

// 创建数据库连接
const dbPath = path.join(app.getPath('userData'), 'app.db');
const db = new Database(dbPath);

// 创建表
db.exec(`
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT UNIQUE,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )
`);

// 插入数据
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
const result = insert.run('John', 'john@example.com');
console.log('插入ID:', result.lastInsertRowid);

// 查询数据
const query = db.prepare('SELECT * FROM users WHERE id = ?');
const user = query.get(1);

// 查询所有
const allUsers = db.prepare('SELECT * FROM users').all();

// 更新数据
const update = db.prepare('UPDATE users SET name = ? WHERE id = ?');
update.run('Jane', 1);

// 删除数据
const deleteStmt = db.prepare('DELETE FROM users WHERE id = ?');
deleteStmt.run(1);

// 关闭连接
db.close();

2.3 事务处理 #

javascript
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');

const insertMany = db.transaction((users) => {
    for (const user of users) {
        insert.run(user.name, user.email);
    }
});

insertMany([
    { name: 'User1', email: 'user1@example.com' },
    { name: 'User2', email: 'user2@example.com' }
]);

2.4 封装 SQLite #

javascript
// database/sqlite.js
const Database = require('better-sqlite3');
const path = require('path');
const { app } = require('electron');

class SQLiteDatabase {
    constructor(dbName = 'app.db') {
        const dbPath = path.join(app.getPath('userData'), dbName);
        this.db = new Database(dbPath);
        this.db.pragma('journal_mode = WAL');
    }

    init() {
        this.db.exec(`
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                email TEXT UNIQUE,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP
            )
        `);
    }

    get(sql, params = []) {
        const stmt = this.db.prepare(sql);
        return stmt.get(...params);
    }

    all(sql, params = []) {
        const stmt = this.db.prepare(sql);
        return stmt.all(...params);
    }

    run(sql, params = []) {
        const stmt = this.db.prepare(sql);
        return stmt.run(...params);
    }

    transaction(fn) {
        return this.db.transaction(fn);
    }

    close() {
        this.db.close();
    }
}

module.exports = SQLiteDatabase;

三、LevelDB #

3.1 安装 #

bash
npm install level

3.2 基本使用 #

javascript
const { Level } = require('level');
const path = require('path');
const { app } = require('electron');

// 创建数据库
const dbPath = path.join(app.getPath('userData'), 'leveldb');
const db = new Level(dbPath, { valueEncoding: 'json' });

// 存储数据
await db.put('user:1', { name: 'John', email: 'john@example.com' });

// 读取数据
const user = await db.get('user:1');

// 删除数据
await db.del('user:1');

// 检查是否存在
try {
    await db.get('key');
    console.log('存在');
} catch (err) {
    if (err.code === 'LEVEL_NOT_FOUND') {
        console.log('不存在');
    }
}

// 批量操作
await db.batch([
    { type: 'put', key: 'user:1', value: { name: 'User1' } },
    { type: 'put', key: 'user:2', value: { name: 'User2' } },
    { type: 'del', key: 'user:3' }
]);

// 遍历所有数据
for await (const [key, value] of db.iterator()) {
    console.log(key, value);
}

// 关闭数据库
await db.close();

3.3 封装 LevelDB #

javascript
// database/leveldb.js
const { Level } = require('level');
const path = require('path');
const { app } = require('electron');

class LevelDBStore {
    constructor(dbName = 'store') {
        const dbPath = path.join(app.getPath('userData'), dbName);
        this.db = new Level(dbPath, { valueEncoding: 'json' });
    }

    async get(key, defaultValue = null) {
        try {
            return await this.db.get(key);
        } catch (err) {
            if (err.code === 'LEVEL_NOT_FOUND') {
                return defaultValue;
            }
            throw err;
        }
    }

    async set(key, value) {
        await this.db.put(key, value);
    }

    async delete(key) {
        await this.db.del(key);
    }

    async has(key) {
        try {
            await this.db.get(key);
            return true;
        } catch {
            return false;
        }
    }

    async clear() {
        await this.db.clear();
    }

    async keys() {
        const keys = [];
        for await (const key of this.db.keys()) {
            keys.push(key);
        }
        return keys;
    }

    async values() {
        const values = [];
        for await (const value of this.db.values()) {
            values.push(value);
        }
        return values;
    }

    async entries() {
        const entries = [];
        for await (const entry of this.db.iterator()) {
            entries.push(entry);
        }
        return entries;
    }

    async close() {
        await this.db.close();
    }
}

module.exports = LevelDBStore;

四、NeDB #

4.1 安装 #

bash
npm install @seald-io/nedb

4.2 基本使用 #

javascript
const Nedb = require('@seald-io/nedb');
const path = require('path');
const { app } = require('electron');

// 创建数据库
const dbPath = path.join(app.getPath('userData'), 'data.db');
const db = new Nedb({ filename: dbPath, autoload: true });

// 插入文档
db.insert({ name: 'John', age: 30 }, (err, doc) => {
    console.log('插入文档:', doc);
});

// Promise 方式
const doc = await db.insertAsync({ name: 'Jane', age: 25 });

// 查询文档
const docs = await db.findAsync({ name: 'John' });

// 查询单个
const doc = await db.findOneAsync({ _id: 'someId' });

// 更新文档
await db.updateAsync(
    { name: 'John' },
    { $set: { age: 31 } },
    { multi: true }
);

// 删除文档
await db.removeAsync({ name: 'John' }, { multi: true });

4.3 封装 NeDB #

javascript
// database/nedb.js
const Nedb = require('@seald-io/nedb');
const path = require('path');
const { app } = require('electron');

class NeDBStore {
    constructor(collection) {
        const dbPath = path.join(app.getPath('userData'), `${collection}.db`);
        this.db = new Nedb({ filename: dbPath, autoload: true });
    }

    async insert(doc) {
        return this.db.insertAsync(doc);
    }

    async find(query = {}, options = {}) {
        let cursor = this.db.findAsync(query);
        
        if (options.sort) {
            cursor = cursor.sort(options.sort);
        }
        if (options.skip) {
            cursor = cursor.skip(options.skip);
        }
        if (options.limit) {
            cursor = cursor.limit(options.limit);
        }
        
        return cursor;
    }

    async findOne(query) {
        return this.db.findOneAsync(query);
    }

    async update(query, update, options = {}) {
        return this.db.updateAsync(query, update, {
            multi: options.multi || false,
            upsert: options.upsert || false,
            returnUpdatedDocs: true
        });
    }

    async remove(query, options = {}) {
        return this.db.removeAsync(query, { multi: options.multi || false });
    }

    async count(query = {}) {
        return this.db.countAsync(query);
    }
}

module.exports = NeDBStore;

五、PouchDB #

5.1 安装 #

bash
npm install pouchdb

5.2 基本使用 #

javascript
const PouchDB = require('pouchdb');
const path = require('path');
const { app } = require('electron');

// 创建本地数据库
const dbPath = path.join(app.getPath('userData'), 'pouchdb');
const db = new PouchDB(dbPath);

// 插入文档
const response = await db.post({
    name: 'John',
    email: 'john@example.com'
});
console.log('插入成功:', response.id);

// 获取文档
const doc = await db.get(response.id);

// 更新文档
await db.put({
    _id: response.id,
    _rev: response.rev,
    name: 'Jane',
    email: 'jane@example.com'
});

// 删除文档
await db.remove(doc);

// 查询所有文档
const result = await db.allDocs({ include_docs: true });
result.rows.forEach(row => {
    console.log(row.doc);
});

5.3 同步功能 #

javascript
// 本地数据库
const localDB = new PouchDB('local');

// 远程数据库
const remoteDB = new PouchDB('http://localhost:5984/mydb');

// 双向同步
localDB.sync(remoteDB, {
    live: true,
    retry: true
}).on('change', (info) => {
    console.log('同步变化:', info);
}).on('error', (err) => {
    console.error('同步错误:', err);
});

六、数据库管理器 #

6.1 统一接口 #

javascript
// database/manager.js
class DatabaseManager {
    constructor() {
        this.connections = new Map();
    }

    getSQLite(name) {
        if (!this.connections.has(name)) {
            const SQLiteDatabase = require('./sqlite');
            this.connections.set(name, new SQLiteDatabase(`${name}.db`));
        }
        return this.connections.get(name);
    }

    getLevelDB(name) {
        if (!this.connections.has(name)) {
            const LevelDBStore = require('./leveldb');
            this.connections.set(name, new LevelDBStore(name));
        }
        return this.connections.get(name);
    }

    getNeDB(name) {
        if (!this.connections.has(name)) {
            const NeDBStore = require('./nedb');
            this.connections.set(name, new NeDBStore(name));
        }
        return this.connections.get(name);
    }

    async closeAll() {
        for (const db of this.connections.values()) {
            if (db.close) {
                await db.close();
            }
        }
        this.connections.clear();
    }
}

module.exports = new DatabaseManager();

6.2 IPC 集成 #

javascript
// main.js
const dbManager = require('./database/manager');

// 初始化数据库
app.whenReady().then(() => {
    const db = dbManager.getSQLite('main');
    db.init();
});

// IPC 处理
ipcMain.handle('db:query', async (event, { db, method, args }) => {
    const database = dbManager.getSQLite(db);
    return database[method](...args);
});

// 应用退出时关闭数据库
app.on('will-quit', async () => {
    await dbManager.closeAll();
});

七、最佳实践 #

7.1 数据库选择指南 #

javascript
function chooseDatabase(requirements) {
    if (requirements.type === 'key-value') {
        return 'LevelDB';
    }
    if (requirements.type === 'relational') {
        return 'SQLite';
    }
    if (requirements.type === 'document') {
        return requirements.sync ? 'PouchDB' : 'NeDB';
    }
    return 'SQLite';
}

7.2 数据备份 #

javascript
const fs = require('fs');
const path = require('path');

async function backupDatabase(dbPath, backupPath) {
    const date = new Date().toISOString().split('T')[0];
    const backupFile = path.join(backupPath, `backup-${date}.db`);
    
    await fs.promises.copyFile(dbPath, backupFile);
    
    return backupFile;
}

7.3 错误处理 #

javascript
async function safeQuery(fn) {
    try {
        return await fn();
    } catch (error) {
        console.error('数据库错误:', error);
        throw new Error('数据库操作失败');
    }
}

八、总结 #

8.1 核心要点 #

要点 说明
SQLite 结构化数据,SQL支持
LevelDB 高性能键值存储
NeDB 简单文档存储
PouchDB 支持同步的文档存储
统一管理 使用管理器统一管理连接

8.2 下一步 #

现在你已经掌握了数据库集成,接下来让我们学习 安全最佳实践,深入了解 Electron 应用的安全防护!

最后更新:2026-03-28