SQLite 是一个单文件的离线关系型 SQL 数据库,它的文件都存储在一个 DB 数据文件中,相比 MySQL 这种数据库服务器来说,SQLite 更方便迁移,对于内存小的服务器来说,使用 SQLite 也是一个不错的选择。SQLite 也可以集成到桌面应用程序中,作为本地数据库使用。

很多编程语言都能操作 SQLite 数据库,Node.js 也不例外。最近我在写一个 Electron 的桌面程序,需要用到 SQLite 作为本地数据库,这里就简单写一下 Node.js 操作 SQLite。

安装 sqlite3 模块

在操作 SQLite 之前还需要先安装 sqlite3 模块,用 npm 安装:

npm install sqlite3 --save-dev

如果在安装的时候出现如下的错误:

gyp ERR! find Python Python is not set from command line or npm configuration
gyp ERR! find Python Python is not set from environment variable PYTHON
gyp ERR! find Python checking if "python" can be used
gyp ERR! find Python - "python" is not in PATH or produced an error
gyp ERR! find Python checking if "python2" can be used
gyp ERR! find Python - "python2" is not in PATH or produced an error
gyp ERR! find Python checking if "python3" can be used
gyp ERR! find Python - "python3" is not in PATH or produced an error

SQLite 模块的编译需要用到 Python,可以下载 Python 安装。

如果安装了最新版的 Python 还是出错的话,可以通过 npm 安装 Python 2,如果用的是 Windows 的话可以通过管理员权限运行 Powershell ,输入:

npm install --global windows-build-tools

安装完 Python 后应该就可以安装 sqlite3 模块了。

打开数据库

下面打开一个 data.db 的数据库:

const sqlite3 = require('sqlite3');  // 引入 sqlite3 模块
const path = require('path');  // 引入路径处理模块

const dbName = path.join(__dirname, 'data.db');  // 获取当前运行目录下的 data.db 文件
// 打开数据库
const db = new sqlite3.Database(dbName, err => {
  if (err !== null) console.log(err);  // 输出错误信息
});

sqlite3.Database 方法可以打开一个数据库,如果传入的 DB 数据库文件不存在就会创建一个,返回一个数据库对象。

如果要关闭打开的数据库可以使用 close 方法,如下:

db.close(err => {
  if (err) console.log(err);
});

回调函数可以接收一个 err 也就是错误信息。

创建数据表

下面创建一张 user 数据表:

// SQL 语句
const sql = `
CREATE TABLE user (
  id INTEGER PRIMARY KEY,
  user_name VARCHAR (30) NOT NULL,
  age TINYINT (3) NOT NULL DEFAULT 0
)
`;
// 创建表格
db.run(sql, function(err) {
  if (err) console.log(err);  // 如果出现错误就输出错误信息

});

这里创建表使用的是 run 方法,run 方法可以执行 SQL 语句,通过回调函数可以获取受影响的行数。不过创建表格是无法获取影响的行数的,只有在 增、删、改 的时候才能获取影响的行数。

添加数据

下面给 user 表添加一条数据:

db.run('INSERT INTO user (user_name, age) VALUES (?, ?)', ['Mark', 28], function(err) {
  if (err) console.log(err);  // 如果有错误就输出错误信息
  console.log(this.changes);  // 输出受影响的行数
  console.log(this.lastID);  // 输出 lastID
});

run 方法可以用于插入、更新、删除 数据,第一个参数的 SQL 语句中包含一些 ?,这个 ? 就是占位符,第二个数组内的内容会替换占位符。上面的 SQL 语句执行的时候如下:

INSERT INTO user (user_name, age) VALUES ('Mark', 28)

第三个参数是一个回调函数,语句执行完成后会执行回调函数,函数的 err 参数可以获取错误信息,函数的 this.changes 可以获取受影响的行数,this.lastID 可以获取 lastID

修改数据

修改数据还是用 run 方法,如下:

db.run('UPDATE user SET user_name = $newName WHERE user_name = $userName', {
  $userName: 'Mark',
  $newName: 'Jack'
}, function(err) {
  if (err) console.log(err);  // 如果有错误就输出错误信息
  console.log(this.changes);  // 输出受影响的行数
  console.log(this.lastID);  // 输出 lastID
});

这里第二个参数是一个对象,对象的值会替换 SQL 语句中和属性名相同的占位符,上面的语句执行的时候如下:

UPDATE user SET user_name = 'Jack' WHERE user_name = 'Mark'

查询数据

删除数据还是用 run 方法,和上面差不多,只是 SQL 语句不一样,这里就不写了。

查询用的表内容如下:

iduser_nameage
1Alice30
2Steve26

下面查询出上面表格中的所有内容:

db.all('SELECT id, user_name, age FROM user', (err, rows) => {
  if (err) console.log(err);  // 如果出现错误就输出错误信息
  console.log(rows);  // 输出查询结果
});

查询出的结果如下:

[
  { id: 1, user_name: 'Alice', age: 30 },
  { id: 2, user_name: 'Steve', age: 26 }
]

下面只查询 user_nameSteve 的数据:

db.all('SELECT id, user_name, age FROM user WHERE user_name = ?', ['Steve'], (err, rows) => {
  if (err) console.log(err);  // 如果出现错误就输出错误信息
  console.log(rows);  // 输出查询结果
});

这里的占位符还是和上面的一样。

all 方法可以查询多条数据,第一个参数就是 SQL 语句,后面的参数可以是用来替换占位符的内容,也可以是回调函数,回调函数需要放在最后。回调函数可以接收 errrows 两个参数,err 就是错误信息,rows 是查询结果的数组,如果没有查询出内容 rows 就是一个空数组。

如果你只需要查询一条数据,也就是查询出的数据不会超过一条的话,可以考虑使用 get 方法,get 方法只会查询一条数据,如下:

db.get('SELECT id, user_name, age FROM user', (err, row) => {
  if (err) console.log(err);
  console.log(row);
});

查询结果如下:

{ id: 1, user_name: 'Alice', age: 30 }

虽然上面的表格中有两条数据,但 get 方法只查询出一条。

get 方法的参数和 all 差不多,第一个参数是 SQL 语句,后面的参数可以是用来替换 SQL 中的占位符的内容,也可以是一个回调函数,回调函数需要在最后。函数可以接收 errrowerr 是错误信息,row 是查询结果,如果没有查询出数据 row 就是 undefined