当调用 db.open('testdb') 方法时, Google Gears 会检测是否已经存在名为 "testdb" 的数据库,如果没有,就创建一个新的名为 "testdb" 的数据库。你也许会想知道这些数据库存放在哪里,存放路径因操作系统和浏览器的不同而不同,具体的位置可以参看 http://code.google.com/intl/zh-CN/apis/gears/api_database.html#directories 。中文字符 SQLite 默认是用 utf-8 编码来存储数据库文件,因此能支持中文字符。也许你注意到了,清单 7 所示的代码中有一条插入语句,把中文字符“傅飞”插入到表 emp 里面。需要注意的是,SQLite 不会对 SQL 语句中的字符串自动转换为 utf-8 编码,所以开发人员需要确保这些字符串是正确编码的,方法是将代码文件用 utf-8 编码保存即可。
全文检索
Google Gears 包含了 SQLite 的一个扩展 fts2, 用于支持全文检索功能。fts2 使你能在一个表中类型为 Text 的所有字段上搜索指定的关键字。为了利用 fts2 的全文检索功能,你需要用 fts2 扩展来创建表,如清单 8 所示。
清单 8. 创建支持全文检索的表
var db = google.gears.factory.create('beta.database'); db.open('testdb'); db.execute('create virtual table movie using fts2(name, director, stars)') |
上面的代码会创建一个能支持全文检索的表,这个表有以下特性
- 依然可以用标准的 Insert, Update 和 Delete 语句操作表中的数据,如清单 9 所示。
- 表中 3 个字段 name, director 和 stars 的类型都是 Text 的。
- 表中隐式包含了一个跟表名相同的字段名,该列会在全文检索的时候用到。由于该列的存在,当你用 Insert 语句插入新记录的时候有必要把你要更新的字段列举出来,同样,用 Select 语句检索的时候也要列举出你期望得到哪些字段的值,如清单 9 所示。如果只是用 Select * from movie 检索 , SQLite 将会抛出异常。
清单 9. 操作支持全文检索的表
// 插入几条数据到表 movie var sql = "insert into movie (name,director,stars) values (?, ?, ?)"; db.execute(sql, ['国产凌凌漆', '李力持', '周星驰 谷德昭 李力持']); db.execute(sql, ['功夫', '周星驰', '周星驰 元华']); db.execute(sql, ['The Dark Knight', 'Christopher Nolan', 'Heath Ledger']); // 更新数据 var sql = 'update movie set stars = ? where name=?'; db.execute(sql, ['Heath Ledger,Christian Bale','The Dark Knight']); db.execute(sql, ['周星驰 元华 冯小刚','功夫']) // 删除表格 db.execute('drop table if exists movie'); // 检索数据 db.execute('select name,director,stars from movie order by name'); |
为了能够全文检索上面创建的表,你需要用 “< 表名 | 字段名 > match < 查询字符串 >” 作为检索条件。如果用表名,实际上是用表中隐含的跟表名同名的字段名,这将会检索表中所有类型为 Text 的字段;如果用字段名,这只在指定的字段上进行检索,这种情况并不是全文检索。我们这里用表名作为例子,假设表 movie 中已经有了如表 1 所示的记录,注意 Stars 字段中的人名是用空格隔开的,空格是 fts2 的分词符, fts2 全文检索的时候是按词来索引的,如果一个字段值没有包含一个空格,该字段值将被视为一个词。
表 1. 表 movie 的所有记录
Name | Director | Stars |
国产凌凌漆 | 李力持 | 周星驰 谷德昭 李力持 |
功夫 | 周星驰 | 周星驰 元华 冯小刚 |
叶问 | 叶伟信 | 甄子丹 任达华 |
非诚勿扰 | 冯小刚 | 葛优 范伟 |
The Dark Knight | Christopher Nolan | Heath Ledger |
Forrest Gump | Robert Zemeckis | Tom Hanks |
我们现在用清单 10 所示的全文检索语句来检索 movie 表,其中查询字符串是“周星驰”。
清单 10. 全文检索的 Select 语句
var sql = 'select name,director,stars from movie where movie match ?'; var rs = db.execute(sql,['周星驰']); |
我们将得到如表 2 所示的结果,可以看出,表 movie 中任何一个字段,只要包含“周星驰”, SQLite 都会将该记录返回给结果集。
表 2. 检索任意字段中包含'周星驰'的记录
Name | Director | Stars |
国产凌凌漆 | 李力持 | 周星驰 谷德昭 李力持 |
功夫 | 周星驰 | 周星驰 元华 冯小刚 |
查询字符串本身也有自己的语法,表 3 中列举出了一些例子。
表 3. 查询字符串的语法
语法例子 | 描述 |
movie match '周星驰 冯小刚' | 返回任意一个字段中既包含“周星驰”又包含“冯小刚”的记录 |
movie match '周星驰 OR 冯小刚' | 返回任意一个字段中包含“周星驰”和“冯小刚”两者中的任一个的记录,OR 必须大写。 |
movie match '国产 *' | 返回任意一个字段中包含以“国产”字符起头的词的记录 |
movie match 'stars: 周星驰 国产 *' | 返回的记录必须满足下面两个条件:
|
movie match '"周星驰 元华"' | 返回的记录必须满足以下条件: 任意一个字段中“元华”紧跟着“周星驰” |
movie match '"周星驰 –冯小刚"' | 返回的记录必须满足下面两个条件:
|
不适合存到本地的数据
有了本地浏览器数据库,你可以尽量多地把数据存放到本地,因为访问本地浏览器数据确实比访问服务器端的数据要快得多。然而不是所有的数据都适合存放到本地,有些情况下你还是需要去服务器端获取数据,下面列举了一些例子。
- 频繁更新的数据,将这种数据保存到本地意义不是很大,因为这种数据很短时间就会过时,比如股票价格,期货价格和等。
- 不常用的数据,比如存储用户偏好信息的数据,这些数据很少使用,如果将这类数据存放到本地,所需的成本也许还大于所带来的收益。
- 太大的数据,由于客户端的硬盘空间有限,不能将这些数据悉数存到本地。
数据同步
对于支持离线模式的 Web 应用程序来说,数据同步显然是一个很重要的话题,一般以下两种情况会用到数据同步:
- 当应用程序离线时,需要将服务器端的最新数据同步到本地,这样才能确保离线时 Web 应用程序照样能运行。
- 当应用程序离线后,用户使用 Web 应用程序时所产生的数据存放在本地,这部分数据需要在连上网络的时候同步到服务器端。
Google Gears 本身并没有提供数据同步 API, 你需要自己实现数据同步的功能,这涉及到浏览器端代码和服务器端代码。下面我们介绍两种实现数据同步功能的思路。
显式同步
这是一种最常见也是最简单的同步方法,用户可以决定什么时候进行同步,实现上可以显式地放置一个同步按钮在网页上,点击该按钮将触发数据同步,把本地新的数据上传到服务器端,并把服务器端新的数据下载到本地。