正在物色node上面的轻量级嵌入式数据库,作为嵌入式数据库的代表,sqlite无疑是个理想的选择方案。npm上集成sqlite的库主要有两个——sqlite3和realm。
realm是一个理想的选择方案,它最初是为移动app设计的,在node也可以运行的,但是不支持Windows系统。sqlite3是一个专为nodejs设计的,在nodejs上面生态更健壮,因此最终选择sqlite3。
sqlite3几乎支持所有版本的nodejs,同时也可以和nwjs集成。
安装
基于npm安装
npm install sqlite3
这样除了安装完sqlite3的npm包,最主要的是也装完了sqlite数据库,因为sqlite是嵌入式数据库,嵌入到客户端中。sqlite3使用node-pre-gyp为各个平台下载指定的预编译的二进制文件。如果无法下载到预编译的二进制文件,sqlite3将使用node-gyp和源代码来构建扩展。
这个过程出现两个的库——node-pre-gyp和node-gyp。他们究竟是什么呢?
node-gyp是一个跨平台的命令行工具,用于编译C++编写的nodejs扩展,首先gyp是为Chromium项目创建的项目生成工具,可以从平台无关的配置生成平台相关的Visual Studio、Xcode、Makefile的项目文件,node-gyp就是将其集成到nodejs中。因为linux的二进制分发快平台做的并不好,所有npm为了方便干脆就直接源码分发,用户装的时候再现场编译。不过对有些项目二进制分发就比源码分发简单多了,所以还有个node-pre-gyp来直接二进制扩展的分发。
两者区别在于node-gyp是发布扩展的源码,然后安装时候编译;node-pre-gyp是直接发布编译后的二级制形式的扩展。
和sqlite3一样的需要基于node-gyp安装的npm模块也有很多,比如node-sass等,都是发布源代码,然后编译安装。
基础api
sqlite3的api都是基于函数回调的,因为nodejs中没有像java的jdbc那种官方的数据库客户端接口,因此每个数据库的api都不一样,这里简单介绍几个sqlite3重要的api。
新建并打开数据库
new sqlite3.Database(filename, [mode], [callback])
该方法返回一个自动打开的数据库对象,参数:
filename:有效值是一个文件名,如:“mydatebase.db”,数据库打开之后会创建一个“mydatebase.db”的文件用于保存数据。如果文件名是“:memory:”,表示是一个内存数据库(类似h2那种),数据不会持久化保存,当关闭数据库时,内容将丢失。
mode(可选):数据库的模式,共3种值:sqlite3.OPEN_READONLY(只读),sqlite3.OPEN_READWRITE(可读写)和sqlite3.OPEN_CREATE(可以创建)。 默认值为OPEN_READWRITE |OPEN_CREATE。
callback(可选):则当数据库成功打开或发生错误时,将调用此函数。 第一个参数是一个错误对象,当它为空时,表示打开成功。
打开一个数据库,如:
//数据库的名字是"mydatebase.db" var database; database = new sqlite3.Database("mydatebase.db", function(e){ if (err) throw err; }); //也可以使用内存型,数据不会永久保存 database = new sqlite3.Database(":memory:", function(e){ if (err) throw err; });
执行后会在项目的根目录生成一个“mydatebase.db”文件,这就是sqlite保存数据的文件了。
关闭数据库
Database#close([callback])
该方法可以关闭一个数据库连接对象,参数:
callback(可选):关闭成功的回调。 第一个参数是一个错误对象,当它为“null”时,表示关闭成功。
执行DDL和DML语句
Database#run(sql, [param, ...], [callback])
该方法可以执行DDL和DML语句,如建表、删除表、删除行数据、插入行数据等,参数:
sql:要运行的SQL字符串。sql的类型是DDL和DML,DQL不能使用这个命令。执行后返回值不包含任何结果,必须通过callback回调函数获取执行结果。
param,...(可选):当SQL语句包含占位符(?)时,这里可以传对应的参数。 这里有三种传值方法,如:
// 直接通过参数传值. db.run("UPDATE tbl SET name = ? WHERE id = ?", "bar", 2); // 将值封装为一个数组传值. db.run("UPDATE tbl SET name = ? WHERE id = ?", [ "bar", 2 ]); // 使用一个json传值.参数的前缀可以是“:name”,“@name”和“$name”。推荐用“$name”形式 db.run("UPDATE tbl SET name = $name WHERE id = $id", { $id: 2, $name: "bar" });
关于占位符的命名,sqlite3还支持更复杂的形式,这里不再扩展,有兴趣了解的话请查看官方文档。
callback(可选):如果执行成功,则第一个参数为null,否则就是出错。
如果执行成功,上下文this包含两个属性:lastID和changes。lastID表示在执行INSERT命令语句时,最后一条数据的id;changes表示UPADTE命令和DELETE命令时候,影响的数据行数。
db.run("UPDATE foo SET id = 1 WHERE id <= 500", function(err) { if (err) throw err; //使用this.changes获取改变的行数 assert.equal(500, this.changes); done(); });
执行多条语句
Database#exec(sql, [callback])
Database#exec与Database#run函数一样,都是DDL和DML语句,但是Database#exec可以执行多条语句,并且不支持占位符参数。