nodejs集成sqlite使⽤⽰例
正在物⾊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可以执⾏多条语句,并且不⽀持占位符参数。
database.run("CREATE TABLE foo (id INT)", function(e){
if(e !== null){
throw e;
}
//循环⽣成sql语句,批次插⼊多条数据
var sql = "";
for(var i = 0 ; i < 500; i ++){
sql += 'INSERT INTO foo VALUES(' + i + ');'
}
<(sql, done)
});
查询⼀条数据
Database#get(sql, [param, ...], [callback])
sql:要运⾏的SQL字符串。sql的类型是DQL。这⾥仅返回第⼀条查询到的数据。
param,...(可选):同Database#run的param参数
callback(可选):同样是返回null代表执⾏成功。回调的签名是function(err,row)。如果查询结果集为空,则第⼆个参数
为undefined;否则第⼆个参数值是查询到的第⼀个对象,他是个json对象,属性名称对应于结果集的列名称,因此查询的每⼀列都应该给出⼀个列表名。
查询所有数据
Database#all(sql, [param, ...], [callback])
nodejs字符串转数组sql:要运⾏的SQL字符串。sql的类型是DQL。和Database#get不同,Database#all会返回所有查询到的语句。param,...(可选):同Database#run的param参数
callback(可选):同样是返回null代表执⾏成功。回调的签名是function(err, rows) 。rows是⼀个数组,如果查询结果集为空数组。
! 注意,Database#all⾸先检索所有结果⾏并将其存储在内存中。对于数据量可能很⼤的查询命令时候,请使⽤Database#each函数或Database#prepare代替这个⽅法。
遍历数据
Database#each(sql, [param, ...], [callback], [complete])
与Database#run函数相同,都是查询多条数据,但是具有以下区别:
回调的签名是function(err,row)。如果结果集成功但为空,则不会调⽤回调。对于每个检索到的⾏,该⽅法都会调⽤⼀次回调。执⾏顺序与结果集中的⾏顺序完全对应。
调⽤所有⾏回调后,如果存在complete回调函数,将调⽤这个回调。第⼀个参数是⼀个错误对象,第⼆个参数是检索⾏数。
语句执⾏顺序
sqlite3的API都是异步的,这就会出现可能有若⼲个命令同时进⾏的情况,因此sqlite3提供了两个函数来帮助控制语句的执⾏流程。默认是并⾏模式。
序列化执⾏
Database#serialize([callback])
如果提供回调,它将⽴即被调⽤,即此⽅法的回调不是异步回调。在该回调中调度的所有数据库语句将被序列化运⾏,即⼀个接⼀个地执⾏。函数返回后,数据库将再次设置为其原始模式。
// 这⾥执⾏的命令是并⾏的
db.serialize(function() {
// 这⾥执⾏的命令是串⾏的
db.serialize(function() {
// 这⾥执⾏的命令是串⾏的
});
// 这⾥执⾏的命令是串⾏的
});
// 这⾥执⾏的命令是并⾏的
并⾏执⾏模式
Database#parallelize([callback])
如果提供回调,它将⽴即被调⽤,即此⽅法的回调不是异步回调。在该回调中调度的所有数据库语句将并⾏运⾏。函数返回后,数据库将再次设置为其原始模式。
db.serialize(function() {
// 这⾥执⾏的命令是串⾏的
db.parallelize(function() {
// 这⾥执⾏的命令是并⾏的
});
// 这⾥执⾏的命令是串⾏的
});
预编译SQL相关api
在java的jdbc中,有个PreparedStatement相关的api,可以预编译sql语句,执⾏的时候再链接具体参数。这样的好处是可以减少sql语句被编译的次数。在sqlite3中,也存在实现这样功能的api。
Database#prepare(sql, [param, ...], [callback])
Database#prepare执⾏后,会返回⼀个命令对象,这个命令对象可以反复执⾏。下⾯看看这个命令对象(statement )的api:
Statement#run([param, ...], [callback])
Statement#get([param, ...], [callback])
Statement#all([param, ...], [callback])
Statement#each([param, ...], [callback])
以上api⽅法与Database的同名⽅法调⽤⽅式相同。不同点是这⾥的Statement对象是可以复⽤的,避免了重复编译sql语句,因此项⽬中更推荐使⽤上述⽅法。
! 注意,这些⽅法的param参数都会对Statement对象绑定参数,在下⼀次执⾏的时候,如果没有重新绑定参数,是会使⽤上⼀次参数的。
绑定参数
Statement#bind([param, ...], [callback])
Database#prepare执⾏的时候,是可以绑定参数的。不过使⽤此⽅法可以全重置语句对象和⾏游标,并删除所有先前绑定的参数,实现重新绑定的功能。
重置语句的⾏游标
Statement#reset([callback])
重置语句的⾏游标,并保留参数绑定。使⽤此功能可以使⽤相同的绑定重新执⾏相同的查询。
数据库事务
事务是关系型数据库中的⼀个重要部分,sqlite⾃然也是⽀持事务的,但是sqlite3并没有提供特殊API去实现的事务相关的操作,只能靠SQL语句去控制事务。这⾥举⼀个事务相关的例⼦。
var db = new sqlite3.Database(db_path);
db.run("CREATE TABLE foo (id INT, txt TEXT)");
db.run("BEGIN TRANSACTION");
var stmt = db.prepare("INSERT INTO foo VALUES(?, ?)");
for (var i = 0; i < count; i++) {
stmt.run(i, randomString());
}
db.run("COMMIT TRANSACTION");
对SQLCipher的⽀持
SQLCipher是⼀个在SQLite基础之上进⾏扩展的开源数据库,他和SQLite不同就是提供了对数据的加密,可提供数据库⽂件的透明256位AES加密。
sqlite3的官⽹特意提及他对SQLCipher的集成,如果要集成sqlcipher需要在编译时候通过构建选项告诉sqlite3要集成的是SQLCipher:
npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/
node -e 'require("sqlite3")'
不过笔者并没尝试对SQLCipher的集成,具体集成⽅法请⾃⾏查阅官⽹对这部分的详细介绍。
基于promise对sqlite3API的封装
sqlite3的API是node早期的API风格,对异步的书写风格并不友好,很容易出现“⾦字塔回调”式的代码。为了让对API的调⽤更加优雅,我们往往会把回调封装成Promise。事实上这个⼯作并不需要我们⾃⼰做,
sqlite3⽣态下已经有其他库可以实现这样的功能。sqlite就是⼀个这样的库。他基于sqlite3,只⼿⽤Promise重新封装了⼀下sqlite3的API,使其代码风格更加优雅,也更容易使⽤。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。