我正在开始开发具有脱机数据库存储要求的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数据库,但仅仅因为我习惯了SQLite,我喜欢SQL的强大和表现力,而且我理解关系模型.对我来说,IndexedDB是一种不确定性.
那就是说,我害怕赌错马.假设支持Web SQL数据库将继续存在,即使IndexedDB成为标准,是否安全?
(关于CouchDB的说明:您是否也将其视为替代方案?)
好吧,就像所有计算一样,游戏是"抽象".
如果您能够提供适用于SQL存储和键/值存储的适当层,那么理想情况下,您可以与问题隔离并支持特定浏览器上的相应实现.如果您的数据模型和访问模式不适合最低公分母(即ak/v商店),那么这就解决了您的问题.
如果您可以使用任一商店,那么就可以在一个合适的访问层上工作,并从该方向处理问题.
请注意,仅仅因为您在后端有ak/v存储并不意味着您必须将数据建模为仅仅ak/v模型.基本上所有DB都在后端是ak/v存储.如果您没有疯狂的数据量,您可以做很多事情.对于大量数据,您可能需要跳过的箍可能会花费您的性能,而您可能无法通过较少的数据看到这些数据.一切都取决于
考虑到只有WebSQL支持您列出的所有三个要求,您的选择不应该简单吗?您无法深入了解Safari或Android的开发路线图,因此请使用您可用的内容.
您的数据库是否需要显着超出键/值存储?如果没有,我发现了一些基于浏览器的数据库抽象的javascript包.一个这样的包是jStore:
http://code.google.com/p/jquery-jstore/
我最近用它来添加本地密钥/值存储.它有详细记录,集成时间可以忽略不计 - 它通过其API支持一系列存储后端,包括闪存本地存储.
CouchDB是一个很好的解决方案 - 对于一个与你的问题不完全相同的问题.看看couchone手机.不是严格的"网络应用程序",但如果您对规范有一定的灵活性,它可能会提供您可以运行的数据库基础.
我的建议是去IndexDB,因为有一个IndexDB Polyfill可用.
支持WebSQL的所有浏览器都可以通过这种方式支持IndexDB API.反过来非常难以实现,因此如果您想要访问所有了解某些DB API的浏览器,IndexDB是当今最好的选择.
注意:即使这个问题很老,它仍然是相关的,所以我认为这个问题的答案值得更新.对于仅链接解决方案感到抱歉,所以我只添加了通常持久目的地的链接:W3C和GitHub
根据您在iOS上对Safari的要求,除了WebSQL之外别无选择.其他移动浏览器(如Opera和Blackberry)支持WebSQL.即使他们有IndexedDB,我也不认为他们会删除WebSQL支持.不知何故,他们是互补的.
另一方面,在浏览器存储战争中,IndexedDB获胜.IE和FF只有IndexedDB.讽刺的是,FF在Sqlite之上实现了IndexedDB.
我想说的是IndexedDB不仅仅是关键值存储.它有索引和交易.这些只有两个几乎构成SQL查询的所有功能,包括连接,条件和排序.起初并不明显,因为它的异步API.
IndexedDB的性能优于WebSQL.它更安全.它对javascript用例更灵活.最后它更容易使用.
为了说明这种情况,我将使用我的库中的 sudo代码,但您可以直接使用IndexedDB API:
'people'商店有索引字段'name'和list indexed字段'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
使用sorted-merge算法查找匹配的键,但这里显示了朴素的嵌套循环连接算法.因此表连接是可能的,但您必须编写连接算法.但是像Zigzag merge这样的新算法比使用Sqlite更快,因为所有输入都是排序的,游标可以很好地进步,更重要的是加入过程可以利用不在数据库中的外部知识.使用SQL,连接操作是不透明的.
除了IndexedDB之外,还可以使用流式传输和map/reduce处理等技术.
我在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由你的真正维护:).