HTML5 IndexedDB、Web SQL 数据库和浏览器大战

Posted

技术标签:

【中文标题】HTML5 IndexedDB、Web SQL 数据库和浏览器大战【英文标题】:HTML5 IndexedDB, Web SQL Database and browser wars 【发布时间】:2011-04-27 16:10:54 【问题描述】:

我开始开发具有离线数据库存储要求的网络应用程序。长话短说,该应用应该能够在以下设备上运行:

主要桌面浏览器之一,首选 Chrome ios 上的 Safari android 的原生浏览器(基于 V8 和 WebKit)

那么问题是选择哪种技术:IndexedDB 还是 Web SQL 数据库?

关于 Web SQL 数据库,一方面,它已准备好用于上述任何场景。另一方面,Mozilla 表示 Firefox 永远不会实现它,并且根据 html5 working draft 规范已经陷入僵局:

这个规范已经陷入僵局:所有感兴趣的实现者都使用了相同的 SQL 后端(Sqlite),但是我们需要多个独立的实现来沿着标准化路径前进。在另一个实现者对实现这个规范感兴趣之前,SQL 方言的描述一直只是对 Sqlite 的简单引用,这对于标准来说是不可接受的。如果您是一名有兴趣实现独立 SQL 后端的实现者,请联系编辑,以便他可以为该方言编写规范,从而使该规范向前发展。

IndexedDB 是 Mozilla 提倡的替代方案,但它只会出现在 Firefox 4 中。微软对此很感兴趣,Chrome 也会支持它。我对 Apple 关于 IndexedDB 的计划一无所知。

我个人倾向于选择Web SQL Database,但正因为习惯了SQLite,我喜欢SQL的强大和表现力,并且理解关系模型。 IndexedDB 对我来说是一个不确定因素。

也就是说,我怕赌错了马。假设对 Web SQL 数据库的支持将继续存在是否安全,即使 IndexedDB 成为标准?

(关于 CouchDB 的注释:您是否也将其视为替代方案?)

【问题讨论】:

【参考方案1】:

考虑到只有 WebSQL 支持您列出的所有三个要求,您的选择不应该很简单吗?您对 Safari 或 Android 的开发路线图一无所知,因此请使用您现有的资源。

【讨论】:

是的,问题在于我将承担的风险。 WebSQL 最终会被淘汰吗?它退出只是时间问题,还是我可以放心地假设它会继续受到支持,尽管可能不在积极的功能开发中?是否有任何我没有考虑的信息可以让我做出更明智的选择?谢谢。 对于 Web SQL 或 IndexedDB 的长期支持实际上还没有任何具体的计划。如果您真的想降低风险,您总是可以绕过 SQL 替代方案并使用 JSON 序列化库将内容存储在 HTML5 localStorage 或 sessionStorage 中。 刚刚发现 webSQL(和 localStorage)在 iOS 5.0.1 中不再持久化。存储 webSQL 数据的位置现在由操作系统定期清理。如果您使用的是 Phonegap/Cordova,则正在开发插件解决方法。 issues.apache.org/jira/browse/CB-330 仅供参考:Apache/Cordova/PhoneGap 同时修复了问题 关于支持的说明:WebSQL 目前在所有主流操作系统版本(iOS7、Android KiKat)上的所有浏览器上都受支持,因此它在一段时间内仍然是一个选项。【参考方案2】:

您的数据库是否需要远远超出键/值存储?如果没有,我发现了许多用于本地基于浏览器的数据库抽象的 javascript 包。 jStore 就是一个这样的包:

http://code.google.com/p/jquery-jstore/

我最近用它来添加本地键/值存储。它有据可查,集成时间可以忽略不计——它通过其 API 支持一系列存储后端,包括闪存本地存储。

CouchDB 是一个出色的解决方案——对于与您的问题不太一致的问题。查看couchone mobile。不适用于严格的“网络应用程序”,但如果您对规范有一定的灵活性,它可能会提供您可以运行的数据库基础。

【讨论】:

【参考方案3】:

嗯,就像所有的计算一样,游戏是“抽象的”。

如果您能想出一个适用于 SQL 存储和键/值存储的适当层,那么理想情况下,您将与问题隔离开来,并且可以支持特定浏览器上的适当实现。如果您的数据模型和访问模式不符合最低公分母(即 k/v 存储),那么这几乎可以解决您的问题。

如果你可以使用任何一个商店,那么就在一个不错的访问层上工作并从那个方向解决问题。

请注意,仅仅因为您在后端有一个 k/v 存储并不意味着您必须将您的数据建模为一个 k/v 模型。本质上,后端的所有数据库都是 k/v 存储。如果你没有大量的数据,你可以做很多事情。对于大量数据,您可能不得不跳过的障碍可能会降低您在使用少量数据时可能看不到的性能。一切都取决于。

【讨论】:

【参考方案4】:

根据您对 iOS 上 Safari 的给定要求,除了 WebSQL 之外别无选择。其他移动浏览器(如 Opera 和 Blackberry)支持 WebSQL。我认为即使他们有 IndexedDB,他们也不会删除 WebSQL 支持。不知何故,它们是互补的。

另一方面,在浏览器存储大战中,IndexedDB 取得了胜利。 IE 和 FF 将只有 IndexedDB。具有讽刺意味的是,FF 在 Sqlite 之上实现了 IndexedDB。

我想说的是,IndexedDB 不仅仅是一个键值存储。它有索引和事务。仅这两者就提供了 SQL 查询的几乎所有功能,包括连接、条件和排序。由于它的异步 API,一开始并不明显。

IndexedDB 的性能优于 WebSQL。它更安全。对于 javascript 用例,它更加灵活。最后,它更易于使用。

为了说明这个例子,我将使用my library的伪代码,但你可以直接使用IndexedDB API:

“人”商店有索引字段“姓名”和列表索引字段“爱好”。在 JSON 中,

people = 
  name: 'Foo Bar',
  email: 'foo@bar.com'
  hobby: ['camping', 'swimming']
;

从爱好“露营”的“人”中检索姓名。

var req = db.keys('people', 'hobby', IDBKeyRange.only('camping'));
req.done(function(campers) 
  db.keys('people', campers, 'name').done(function(names) 
     console.log(names);
  );
);

这段代码的有趣之处在于没有涉及序列化。因此速度非常快。

以下示例说明了友谊图查询。 friendship 对象存储只有一个列出的索引字段 friend_list。它使用人员对象存储键作为离线主键。 people对象存储有很多属性,其中有location字段。查询是查找认识meother_guy且位于'Singapore'的朋友列表。

var q1 = new ydn.db.Iterator('friendship', 'friend_list', IDBKeyRange.only(me));
var q2 = new dn.db.Iterator('friendship', 'friend_list', IDBKeyRange.only(other_guy));
// if location is not indexed, a filtered value query is used.
var q3 = new ydn.db.Iterator('people', new ydn.db.Expression(['"location"', "'Singapore'", '=']));
// if location is indexed, an index query is used.
// var q3 = new ydn.db.Iterator('people', 'location', IDBKeyRange.only('Singapore'));
var current_loop = 2; // start from inner loop
var join_algo = function(keys, index_keys) 
  var advancement = [];
  advancement[keys.length - 1] = null;
  var has_adv = false;
  for (var i = 0; i < keys.length; i++) 
    if (!goog.isDef(keys[i])) 
      // completed iterator
      if (i != 0) 
        advancement[i] = false; // request to restart the iteration
        advancement[i - 1] = true; // advance outer iterator
        current_loop = i - 1;
       // i == 0 means we are done.
    has_adv = true;
    break;
    
  
  if (!has_adv) 
    // continue looping current
    advancement[current_loop] = true;
  
  return advancement;

var result = db.scan([q3, q1, q2], join_algo);
result.done(function(keys, index_keys, values) 
  console.log(values); // should get desire list of friends 
);

同样,此连接查询只是键扫描,因此速度非常快。默认情况下scan 使用排序合并算法来查找匹配的键,但这里显示的是一个简单的嵌套循环连接算法。所以表连接是可能的,但你必须编写连接算法。但是像 zigzag 合并这样的新算法比使用 Sqlite 更快,因为所有输入都已排序,游标也可以前进,更重要的是,连接过程可以利用数据库中没有的外部知识。使用 SQL,连接操作是不透明的。

除了 IndexedDB 之外,还可以使用流式处理和 map/reduce 处理等技术。

【讨论】:

【参考方案5】:

我的建议是使用 IndexDB,因为有一个 IndexDB Polyfill 可用。

所有支持WebSQL的浏览器都可以通过这种方式支持IndexDB API。反之则很难实现,所以如果你想覆盖所有知道某些 DB API 的浏览器,IndexDB 是当今最好的选择。


注意:即使这个问题很老,它仍然是相关的,所以我认为这个问题的答案值得更新。对仅链接的解决方案感到抱歉,所以我只添加了指向通常持久目的地的链接:W3C 和 GitHub

【讨论】:

【参考方案6】:

我将在 2016 年(在您提出这个问题 5 年后)回复此问题以及与 deprecation of WebSQL still stands 有关的所有内容。另一方面,IndexedDB,enjoys the support of all of the major browser vendors。

因此,对于可能发现自己在这里面临同样决定的任何人,请选择 IndexedDB。

然而,正如这里其他人所暗示的那样,这样的决定并不是必须做出的;可以简单地选择(或制作)一个库,该库利用客户端计算机上可用的任何数据库。

BakedGoods 与此处已建议的此类库在几个方面有所不同;最相关的是,它允许明确指定要使用的存储类型,进而允许开发人员在决策过程中引入其他因素(例如性能特征)。

有了它,在支持的任何一种数据库类型中执行存储操作都是...

...为两种数据库类型指定适当的操作选项和等效配置:

//If the operation is a set(), and the referenced structures 
//don't exist, they will be created automatically.

var webSQLOptionsObj = 
    databaseName: "Example_DB",
    databaseDisplayName: "Example DB",
    databaseVersion: "",
    estimatedDatabaseSize: 1024 * 1024,
    tableData: 
        name: "Main",
        keyColumnName: "lastName",
        columnDefinitions: "(lastName TEXT PRIMARY KEY, firstName TEXT)"
    , 
    tableIndexDataArray: [name: "First_Name_Index", columnNames: "(firstName)"]
;

var indexedDBOptionsObj = 
    databaseName: "Example_DB",
    databaseVersion: 1,
    objectStoreData: 
        name: "Main",
        keyPath: lastName,
        autoIncrement: false
    ,
    objectStoreIndexDataArray: [
        name: "First_Name_Index", keyPath: "firstName", unique: false, multiEntry: false
    ],
;

var optionsObj = 
    conductDisjointly: false, 
    webSQL: webSQLOptionsObj, 
    indexedDB: indexedDBOptionsObj
;

...并进行操作:

bakedGoods.set(
    data: [
        value: lastName: "Obama", firstName: "Barack", 
        value: lastName: "Biden", firstName: "Joe"
    ],
    storageTypes: ["indexedDB", "webSQL"],
    options: optionsObj,
    complete: function(byStorageTypeStoredItemRangeDataObj, byStorageTypeErrorObj)
);

其简单的界面和无与伦比的存储设施支持是以缺乏对某些存储设施特定配置的支持为代价的。例如,它不支持在具有多列主键的 WebSQL 表中进行存储操作。

因此,如果您大量使用这些类型的功能,您可能想看看其他地方。

哦,为了完全透明,BakedGoods 确实由您维护 :)。

【讨论】:

以上是关于HTML5 IndexedDB、Web SQL 数据库和浏览器大战的主要内容,如果未能解决你的问题,请参考以下文章

web API简介:客户端储存之IndexedDB API

web网站使用indexedDB缓存大数量案例

堪比Web SQL:开源项目让IDB速度原地提升数十倍

HTML5中indexedDB存储离线数据示例

indexedDB 在概念上与 HTML5 本地存储有何不同?

怎么判断浏览器是不是支持html5的indexedDB