HTML5 的 Web SQL Database 用本地和会话存储实现简单的对象持久化,对繁琐的关系数据进行处理。
在 W3C 的 Web SQL Database 规范中(参照 介绍 )有这样的描述:Web SQL Database 引入了一套使用 SQL 来操纵客户端数据库(client-side database)的 API,这些 API 是异步的(asynchronous),所以作者在使用这套 API 时会发现匿名函数非常有用。
Web SQL Database 规范中定义的三个核心方法:
1、openDatabase:这个方法使用现有数据库或创建新数据库创建数据库对象。
2、transaction:这个方法允许我们根据情况控制事务提交或回滚。
3、executeSql:这个方法用于执行真实的SQL查询
打开数据库
openDatabase方法可以打开已经存在的数据库,不存在则创建:
var db = openDatabase('mydatabase', '1.0', my db', 2 * 1024);
openDatabasek中五个参数分别为:数据库名、版本号、描述、数据库大小、创建回调。创建回调没有也可以创建数据库。
执行查询
database.transaction()函数用来查询,下面将在mydatabase数据库中创建表t1:
var db = openDatabase(' mydatabase ', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
});
插入操作
var db = openDatabase('mydatabase', '2.0', my db', 2 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (2, "logmsg")');
});
在插入新记录时,我们还可以传递动态值,如:
var db = openDatabase(' mydatabase ', '2.0', 'my db', 2 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
tx.executeSql('INSERT INTO t1
(id,log) VALUES (?, ?'), [e_id, e_log]; //e_id和e_log是外部变量
});
读操作
如果要读取已经存在的记录,我们使用一个回调捕获结果,代码如下:
var db = openDatabase(mydatabase, '2.0', 'my db', 2*1024); db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (2, "logmsg")');
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM t1, [], function (tx, results) {
var len = results.rows.length, i;
msg = "
Found rows: " + len + "
";完整的例子
·下面是网上一段很有用的封装的数据库创建方法
function initDB(){
var myDB = null;
try {
if (!window.openDatabase) {
// 当前浏览器没有数据库支持
alert('db not supported');
} else {
var shortName = 'testdb';
var version = '1.0';
var displayName = 'test offline database';
var maxSize = 65536; // 字节
myDB = openDatabase(shortName, version, displayName, maxSize);
}
} catch(e) {
// 这里开始异常处理 .
if (e == INVALID_STATE_ERR) {
// 数据库版本异常 .
alert("Invalid database version.");
} else {
alert("Unknown error "+e+".");
}
}
// 返回创建好的数据库实例
return myDB;
}
执行数据库语句
所有 SQL 语句的执行都被嵌套在一个事务中,从而保证了数据的完整性和一致性。执行该 SQL 语句的结果以及错误处理需要在 executeSql 函数的最后两个参数中指定,这两个回调方法参数是可以省略的。
var sql1 = 'CREATE TABLE IF NOT EXISTS User(name TEXT, age INTEGER);'
var sql2 = 'INSERT INTO User values(?,?)';
var sql3 = 'SELECT * FROM User WHERE name=?';
var sql4 = 'DELETE FROM User where name=?';
var sql5 = 'UPDATE User SET age=? WHERE name=?';
myDB.transaction(function (tx) {
tx.executeSql(sql,['参数'],function(tx,results){
var len = results.rows.length;
var result = results.rows.item(0).name
},function(tx,error){
});
});
persistence.js
所有的 SQL 操作都需要在指定的函数中做结果处理以及错误处理,而且传统的 SQL 语句写起来也比较费事,这个时候我们都无比怀念 Java 语言中的 ORM 工具。
所幸的是开发社区从来不缺有创意的开发人员,目前已经有不少的开源 Web SQL ORM 工具出现了。
persistence.js 是一个 JavaScript 框架,最初它的设计目标是对 HTML Web SQL 进行 OR Mapping,以方便客户端开发人员进行快速的 Web SQL 访问。
后来随着该框架的发展,它开始逐渐剥离了对数据库的依赖,成为一个可以支持各种数据库的框架。
(1)引入 persistence.js
persistence.js 将其核心模块分割成各个较小的 JavaScript 文件,有效的保证了高性能的加载,用户仅需要在用到某个功能模块时才引入相应的 JavaScript 文件。这里我们用到了 persistence.js,persistence.store.sql.js 和 persistence.store.websql.js,这三个文件是使用 Web SQL 必需的。如果用户想以在内存中临时保存数据的方式作为浏览器不支持 Web SQL API 时的替代,那么也可以将 persistence.store.memory.js 引入进来。
文件下载地址: https://github.com/coresmart/persistencejs
(2)插入和删除数据
对 User 表插入一条记录就是直接将一个 User 对象保存起来,并调用 flush() 方法在持久化。
persistence.js 插入数据
var mark = new User({name: "Mark", age: 60});
persistence.add(mark);
persistence.flush();
删除一条记录就是直接将一个 User 对象删除,如清单 10。
persistence.js 删除数据
persistence.remove(mark);
persistence.flush();
(3)对表之间关联的支持
传统的数据库支持一对多,多对一,多对多的表间关联,这部分功能在很多 Java ORM 工具中已经很好的支持了,在 persistence.js 中,也能发现类似的实现。比如上例中的 User 表,我们需要加入一个新的 Address 表记录 User 对象的地址,每个 User 对象可能有多个地址。我们可以轻易实现表的关联。
var Address = persistence.define('Address', {
detail: "TEXT",
zipcode: "TEXT"
});
User.hasMany(“addresses”, Address, “user”);
persistence.schemaSync();
var addr1 = new Address({detail:”addr1”, zipcode:”code1”});
var addr2 = new Address({detail:”addr2”, zipcode:”code2”});
persistence.add(addr1);
persistence.add(addr2);
mark.addresses.add(addr1);
mark.addresses.add(addr2);
persistence.flush();
hasMany() 方法是每个通过 persistence.define 定义出的对象都有的内置方法,通过执行上述 hasMany() 方法,User 表将会增加一个属性 addresses 作为与 Address 表的关联,并且 addresses 可以关联到多个 Address 对象。而 Address 对象也会 增加一个 user 属性,通过 user 属性将某个 Address 对象关联到一个 User 对象。
类似的,用户也可以调用表对象的 hasOne() 方法来定义 Address 对象仅关联到一个 User 对象。
(4)查询数据
persistence.js 提供了简单而强大的查询语法,查询数据是仅需要相当直观的一两次 API 调用。针对某个表的查询入口实际上就是从 persistence.define 定义出的对象入手。以上文定义的 User 为例。
User.all() 将会直接返回一个 QueryCollection,里面将包含所有的 User 对象。
User.load() 可以根据用户传入的 User 对象 ID 来加载某个 User 对象。
User.findBy() 可以根据用户传入的 User 对象属性以及属性的值来查询出符合条件的 User 对象集合并返回。
User.all().one(function(user){
console.log(user);
}); // 查询出第一个 User 对象
User.load("6C22FD66801C41728AE5A6BCE0A8EE54", function(user){
console.log(user.name);
}); // 查询出 ID 为"6C22FD66801C41728AE5A6BCE0A8EE54"的 User 对象
User.findBy("name", "Mark", function(user){
console.log(user.age);
}); // 查询出 name 是 Mark 的 User 对象
针对查询返回的 QueryCollection,persistence.js 提供了丰富的扩展性功能来整理该集合中的数据,如 filter,or,and,order,limit 等等,感兴趣的读者可以在 persistence.js 的官网上找到相关介绍。
然而!!!
这他喵的就有点尴尬了。
W3C组织在2010年11月18日废弃了webSql。但是并不影响其当前功能的使用,依然很强悍,使用者不在少数。