44

我正在开始开发具有离线数据库存储要求的 Web 应用程序。长话短说,该应用程序应该能够运行:

  • 主流桌面浏览器之一,首选Chrome
  • iOS 上的 Safari
  • Android的原生浏览器(基于V8和WebKit)

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

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

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

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

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

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

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

4

6 回答 6

25

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

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

如果您可以使用任一存储,则在一个不错的访问层上工作并从那个方向解决问题。

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

于 2010-10-28T01:57:08.850 回答
14

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

于 2010-10-19T20:31:44.043 回答
9

我在 2016 年(在你问这个问题 5 年后)回复了这个问题,关于弃用 WebSQL 的一切仍然存在。另一方面,IndexedDB享有所有主要浏览器供应商的支持

因此,对于任何可能发现自己在这里面临同样决定的人来说,选择 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 由您真正维护 :) 。

于 2016-07-08T23:00:09.877 回答
7

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

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


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

于 2013-08-09T10:21:59.380 回答
6

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

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

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

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

于 2010-10-28T00:53:48.777 回答
6

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

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

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

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

为了说明这种情况,我将使用我库中的伪代码,但您可以直接使用 IndexedDB API:

'people' 商店有索引字段 'name' 和列表索引字段 'hobby'。在 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字段。me查询是查找认识并other_guy位于“新加坡”的朋友列表。

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 处理等技术。

于 2012-11-11T03:54:23.170 回答