nativeScript-sqlite
适用于 Android 和 iOS 的 sqlite NativeScript 模块
npm i --save nativescript-sqlite

License License Proplugins NativeScriptCore Twitter Follow

NativeScript sqlite

一个为 Android 和 iOS 提供sqlite操作的 NativeScript 模块。(具有多线程功能)

许可证

该软件有两种可能的许可证;

npm license

NativeScript-Sqlite 免费版

该库的这一部分是在 MIT 许可证下发布的,这意味着您可以将此代码包含在任何类型的程序中 - 但是对于需要支持合同、更改、增强和/或商业许可证的实体,请参阅 http://nativescript.tools

NativeScript-SQLite 商业/加密版本

它还有一个商业许可证版本,允许您在项目中使用该插件的商业版本。

以下是一些商业版本的功能增强:

  • TypeScript 定义
  • 与免费版本完全向后兼容
  • 预处理语句
  • 多级事务支持
  • 加密
  • 每个查询中的多个 SQL 语句
  • 完整的源代码
  • 多线程

注意:在 iOS 上安装加密时,您可能需要删除以下文件: node_modules/nativescript-sqlite/platforms/ios/module.modulemap。然后运行 tns platform clean ios。此文件是正常未加密 sqlite 所必需的;但它可能与某些版本的 XCode 上的加密冲突。当您运行应用程序时;如果您收到有关加密未链接的控制台行,则这是原因。

示例应用程序

可以从 https://github.com/NathanaelA/nativescript-sqlite 下载或克隆示例应用程序。要使用它,您需要执行以下操作

  • npm i
  • tns run

可选

  • tns plugin add nativescript-sqlite-commercial-???.tgz
  • tns plugin add nativescript-sqlite-encrypted-???.tgz
  • tns plugin add nativescript-sqlite-sync-???.tgz

然后按照正常方式运行应用程序。

安装

在您项目的根目录中运行 tns plugin add nativescript-sqlite

可选

  • tns plugin add ./plugins/nativescript-sqlite-commercial-???.tgz
  • tns plugin add ./plugins/nativescript-sqlite-encrypted-???.tgz
  • tns plugin add ./plugins/nativescript-sqlite-sync-???.tgz

Webpacking(NativeScript 8 / Webpack 5)

您不需要做任何事情!它将自动将项目中所有 *.sqlite 文件添加进去。

Webpacking(NativeScript 5、6 和 7 / Webpack 4)

如果您正在将嵌入到您的应用程序中的 SQLite 数据库包含在内,并且您正在使用 Webpack,那么在 webpack.config.js 大约第 100 行有一个看起来是这样的部分

            // Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: { glob: "fonts/**" } },
{ from: { glob: "**/*.jpg" } },
{ from: { glob: "**/*.png" } },
{ from: { glob: "**/*.sqlite" }},
], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] })

添加新行 { from: { glob: "**/*.sqlite" } }, 以在捆绑应用程序时拾取您的 SQLite 文件。

此外,如果您不使用同步、商业或加密插件,您需要将您不使用的任何内容添加到 webpack.config.js 文件中

        externals.push('nativescript-sqlite-commercial');
externals.push('nativescript-sqlite-encrypted');
externals.push('nativescript-sqlite-sync');

以便在 webpacking 时忽略它们,在说 'const externals = nsWebpack.getConvertedExternals(env.externals)' 的行下面

使用方法

要使用 sqlite 模块,您必须首先使用 require()

const Sqlite = require( "nativescript-sqlite" );

(或使用 TypeScript,如果您使用商业版本)

import Sqlite from "nativescript-sqlite";

在您获得模块引用后,您可以调用可用的方法。数据库默认以数组形式返回结果集;即 [[field1, field2, ...], [field1, field2], [field1, field2] ...],如果您愿意,可以将其更改为以对象形式返回。

将数据库与应用程序一起打包

如果您计划将数据库与应用程序一起打包;将文件放入您的项目 /app 文件夹中(使用 Angular 的情况下为 src)。Sqlite.copyDatabase("database_name") 将将数据库从该文件夹复制到您平台上的正确数据库文件夹。

回调函数

  • 所有回调函数都有标准的 (Error, result) 原型
  • 使用 CALLBACK 或 PROMISE;不建议同时使用两者

PROMISE

  • 将调用您的 reject 函数以错误响应,或使用 resolve 函数以答案响应
  • 使用 CALLBACK 或 PROMISE;不建议同时使用两者

常量

  • Sqlite.RESULTSASARRAY - 将结果作为数组返回(例如:select name, phone --- results [[name,phone]])

  • Sqlite.RESULTSASOBJECT - 将结果作为对象返回(例如:select name, phone --- results [{name: name, phone: phone}])

  • Sqlite.VALUESARENATIVE - 将值作为原生值返回;即 Integer = Integer, Float = Number

  • Sqlite.VALUESARESTRINGS - 将所有值作为字符串返回;因此,Integer 1 将返回为 "1"

  • Sqlite.HAS_COMMERCIAL - 如果加载了商业库,则为 true。

  • Sqlite.HAS_ENCRYPTION - 如果加载了加密库,则为 true。

  • Sqlite.HAS_SYNC - 如果加载了同步库,则为 true。

方法

new Sqlite(dbname, options, callback)

promise = Sqlite(dbname, options, callback)

参数
  • dbname: 您的数据库名。这可以是 ":memory:" 以创建内存数据库。这也可以是 "" 以创建临时数据库。
  • options
    • "readOnly",如果设置为 true,则在打开时将数据库设置为只读
    • "key",用于使用/打开加密数据库(参见文档底部的加密,需要商业版本)
    • "multithreading",启用后台多任务。所有 SQL 都在后台工作线程上运行。(需要商业版本)
    • "migrate",将加密的 Sql 数据库从 v3 迁移到新的 v4。如果您是新手用户,您不需要设置此标志,因为新创建的数据库已经处于 v4。如果您正在升级使用 NS-Sqlite-Encrypted v1.3.0 或更早版本的应用程序;那么您可能需要将此标志设置为 true。
  • (可选) callback (error, db):db 是完全打开的数据库对象,允许与数据库交互。
  • 返回:DB 对象的 promise

您应该选择使用 Promise 或回调;您可以使用您最舒适的方式 -- 然而,就像这个示例一样,如果您想,您可以使用两者;但某些函数会有副作用。

// Promise based example
const Sqlite = require( "nativescript-sqlite" );

const db = await Sqlite("MyTable");
console.log("Are we open yet (Promise based)? ", db.isOpen() ? "Yes" : "No"); // Yes

// Callback based example
const Sqlite = require( "nativescript-sqlite" );
new Sqlite("MyTable", function(err, db) {
if (err) {
console.error("We failed to open database", err);
} else {
// This should ALWAYS be true, db object is open in the "Callback" if no errors occurred
console.log("Are we open yet (Callback based)? ", db.isOpen() ? "Yes" : "No"); // Yes
}
});

Sqlite.isSqlite()

参数
  • 要检查的对象
  • 返回:布尔值,如果传递给此函数的对象是 sqlite 数据库,则为 True 或 False
// my-page.js
new Sqlite("test.db", function(err, db) {
console.log("Is a Sqlite Database:", Sqlite.isSqlite(db) ? "Yes" : "No"); // Should print "Yes"
});

Sqlite.exists(dbName)

参数
  • dbName - 数据库名
  • 返回:布尔值,如果数据库存在于应用程序/操作系统数据库文件夹中,则为 True

Sqlite.deleteDatabase(dbName)

  • dbName - 要在应用程序/操作系统数据库文件夹中删除的数据库名
  • 返回:无

Sqlite.copyDatabase(dbName, destName)

  • dbName - 要从您的应用程序文件夹复制到操作系统正确数据库文件夹的数据库名
  • destName - (可选) - 如果您想将数据库目标名称设置为与源不同的名称
  • 返回:如果复制成功,则为 True
  • 注意:如果目标已存在,则不会复制文件。
// If we are in Debug Code, we always delete the database first so that the latest copy of the database is used...
if (DEBUGMODE && Sqlite.exists("mydatabase.sqlite")) {
Sqlite.deleteDatabase("mydatabase.sqlite");
}
if (!Sqlite.exists("mydatabase.sqlite")) {
// Example: Copying a different name to mydatabase.sqlite
// Sqlite.copyDatabase("original.sqlite", "mydatabase.sqlite");
// OR copy mydatabase to where it belongs...
Sqlite.copyDatabase("mydatabase.sqlite");
}

DB 方法 = 构造函数返回的数据库对象

DB.version()

参数
  • 要设置的值,或用于检索值的回调函数。如果回调,值将包含版本。对于新数据库,版本将为零。如果版本号,则数据库将更改为您传递给此函数的版本
  • 返回:Promise。
new Sqlite("test.db", function(err, db) {
db.version(function(err, ver) {
if (ver === 0) {
db.execSQL("Create table....");
db.version(1); // Sets the version to 1
}
});
});

DB.isOpen()

  • 返回值:布尔值,当前数据库是否打开(true/false)。请注意;在多线程中,这个值最初可能是不正确的,因为数据库可能仍在打开过程中。为了兼容性,我们在执行打开操作后在多线程中自动将其设置为true。

DB.resultType(Sqlite.YYY)

参数
  • 传入 Sqlite.RESULTSASOBJECT 或 Sqlite.RESULTSASARRAY 以更改结果集配置。这将使数据库返回您选择的结果。默认为 RESULTSASARRAY。

DB.valueType(Sqlite.YYY)

参数
  • 传入 Sqlite.VALUESARENATIVE 或 Sqlite.VALUESARESTRING 以更改结果集配置。这将使数据库返回您选择的结果。默认为 VALUESARENATIVE。

DB.close()

  • 关闭数据库
  • 返回值:Promise 注意:在此之后进行的任何 DB 调用都将引发错误。

DB.execSQL(SQL语句,params,回调)

DB.execSQL([多个语句],[params],回调) - 商业版功能

参数
  • 要运行的 SQL 语句,可以使用 ? 作为参数
  • Params(可选)- 参数数组
  • 回调将返回 null 或最后一个插入的 id 或更新/删除的记录数。此例程可用于“更新”、“插入”、“删除”和其他任何您不期望返回结果集的 sqlite 命令。如果是插入,它将返回新插入记录的最后一行 id。如果是更新/插入,它将返回受影响的行数。如果您发送多个查询,则将得到一个结果数组。
  • 返回值:Promise;解决的结果与回调值相同。
// new SQLite(....
db.execSQL("insert into Hello (word) values (?)", ["Hi"], function(err, id) {
console.log("The new record id is:", id);
});
// NOTE: Sending Arrays of queries is only available in Commercial version...
// new SQLite(....
const promise = db.execSQL(["insert into Hello (word) values (?)", "insert into Hello (word) values (?)"], [["Hi"], ["Hello"]]);
promise.then(function(ids) {
console.log("The new record ids are:", ids[0], ids[1]);
});

DB.get(语句,params,回调)

DB.get([多个语句],[params],回调) - 商业版功能

参数
  • SQL SELECT 语句,可以使用 ? 作为参数
  • Params(可选)
  • 回调将具有结果集的第一行。
  • 返回值:Promise,将包含第一行。
// new SQLite(...
db.get('select * from Hello where id=?', [1], function(err, row) {
console.log("Row of data was: ", row); // Prints [["Field1", "Field2",...]]
});
// new SQLite(...
const promise = db.get('select * from Hello where id=?', [1]);
promise.then(function(row) {
console.log("Row of data was: ", row); // Prints [["Field1", "Field2",...]]
});

DB.all(查询,params,回调)

DB.all([多个查询],[params],回调) - 商业版功能

参数
  • SQL SELECT 语句,可以使用 ? 作为参数
  • Params(可选)
  • 回调将具有结果集中的所有行。
  • 返回值:Promise,将包含结果集中的所有行。
// new SQLite(...
db.all('select * from Hello where id > ? and id < ?', [1,100], function(err, resultSet) {
console.log("Result set is:", resultSet); // Prints [["Row_1 Field_1" "Row_1 Field_2",...], ["Row 2"...], ...]
});
// new SQLite(...
const promise = db.all('select * from Hello where id > ? and id < ?', [1,100]);
promise.then(function(resultSet) {
console.log("Result set is:", resultSet); // Prints [["Row_1 Field_1" "Row_1 Field_2",...], ["Row 2"...], ...]
});

DB.each()

参数
  • SQL Select 语句,可以使用 ? 作为参数
  • Params(可选)
  • 回调(必需)将为结果集中的每一行调用,并带有当前行的值
  • Finished_Callback(可选)将在完成时调用,并带有处理的行数。
  • 返回值:Promise;请注意,每行的 CALLBACK 仍然是必需的;否则您将没有任何结果...
// new SQLite(...
db.each('select * from Hello where id >= ? and id <= ?', [1, 100],
function (err, row) {
console.log("Row results it:", row); // Prints ["Row x Field_1", "Row x Field 2"...] for each row passed to it
},
function (err, count) {
console.log("Rows displayed:", count); // Prints 100 (Assuming their are a 100 rows found)
});
// new SQLite(...
const promise = db.each('select * from Hello where id >= ? and id <= ?', [1, 100],
function (err, row) {
console.log("Row results it:", row); // Prints ["Row x Field_1", "Row x Field 2"...] for each row passed to it
});
promise.then(function (count) {
console.log("Rows displayed:", count); // Prints 100 (Assuming their are a 100 rows found)
});

仅商业版功能

启用可选功能

启用加密: tns plugin add nativescript-sqlite-encrypted-1.2.1.tgz

启用商业: tns plugin add nativescript-sqlite-commercial-1.2.0.tgz

加密支持

使用 options.key 将加密密钥传递给数据库打开函数,并将应用。请注意,必须使用加密创建数据库才能使用加密。因此,如果您创建了普通数据库,则无法事后添加加密。
如果您传递一个空白("")空密钥,则它将视为没有密钥。但是,如果您需要更现代 sqlite 驱动程序的功能,但不需要加密,它将仍然使用加密驱动程序。

注意:在加密驱动程序中启用/编译会增加大约 3 兆的应用程序 APK 大小(在 Android 上)和大约 2 兆的 iOS 应用程序大小。

加密升级

数据库构造函数中有一个新的升级选项可以传递。如果您使用的是此 NS-Sqlite-Encryption 的旧版本(1.3.0 或更早版本)。

  • "migrate",将加密的 Sql 数据库从 v3 迁移到新的 v4。如果您是新手用户,您不需要设置此标志,因为新创建的数据库已经处于 v4。如果您正在升级使用 NS-Sqlite-Encrypted v1.3.0 或更早版本的应用程序;那么您可能需要将此标志设置为 true。

iOS 加密注意事项

如果您看到 SQLCipher 似乎没有被链接到应用程序

有时 iOS 决定它真正想要使用加密版本而不是标准 SQLite。您可以尝试以下几件事

  • 删除使用加密时不需要的一些文件,这些文件可能会引入标准 sqlite 插件。
    • rm node_modules/nativescript-sqlite/platforms/ios/build.xcconfig
    • 删除 node_modules/nativescript-sqlite/platforms/ios/module.modulemap 文件
    • 然后执行 tns platform clean ios

多任务/多线程

商业版本支持将所有 SQL 访问放入后台线程,这样在执行数据访问时 UI 不会冻结。要启用,只需在创建新的 Sqlite 连接时传递 {multithreading: true} 作为选项。

预编译查询

DB.prepare(SQL)

参数
  • SQL 语句
  • 返回预编译语句

PREPAREDSTATEMENT.execute(param1, param2, param3, optional_callback)

PREPAREDSTATEMENT.execute([param1, param2, param3], optional_callback)

PREPAREDSTATEMENT.execute([ [ p1, p2, p3], [p1, p2, p3], ...], optional_callback)

参数
  • 传入值、值数组或数组数组
  • 最后可选地传入回调函数,当操作完成时使用。
  • 返回一个 Promise

PREPAREDSATEMENT.finished()

  • 清理并销毁此预编译语句。当你完成预编译语句的所有操作时使用。
const prep = db.prepare('insert into names (first, last) values (?,?)');
for (let i=0;i<10;i++) {
prep.execute(["Name", i]);
}
prep.finished();

事务

DB.begin()

参数
  • 回调(可选)
  • RETURNS promise 这将开始一个新的事务,如果你开始一个嵌套事务,直到你提交第一个事务,什么都不会写入。

DB.commit()

参数
  • 回调(可选)
  • RETURNS promise 这将提交单个事务,如果这是一个嵌套事务;更改不会被写入,直到第一个/最终事务被提交。

DB.commitAll()

参数
  • 回调(可选)
  • RETURNS promise 这将提交整个事务组,所有内容都会写入,任何打开的事务都会被提交。

DB.rollback()

参数
  • 回调(可选)
  • RETURNS promise 这将回滚单个事务,如果这是一个嵌套事务;只有最外层的嵌套事务会被回滚。

DB.rollbackAll()

参数
  • 回调(可选)
  • RETURNS promise 这将回滚整个事务组;所有内容都会被取消。

教程

需要更多帮助来开始?请查看这些教程,了解如何在 NativeScript Android 和 iOS 应用中使用 SQLite。

错误说明

  • 如果你收到有关打开 SQL 表的错误 android.database.sqlite.SQLiteException: Failed to change locale for db <dbname> to 'en_US'. 你需要创建表并插入它失败的区域设置
CREATE TABLE android_metadata ( locale TEXT );
insert into android_metadata values ('en_us');

或者将 .androidFlags 的值 16 传递给打开语句。