indexeddb怎么触发onupgrade恋老neededd

前端存储之indexedDB - 再见_孙悟空 - 博客园
在前一个阶段的工作中,项目组要开发一个平台,为了做出更好的用户体验,实现快速、高质量的交互,从而更快得到用户的反馈,要求在前端把数据存储起来,之后我去研究了下现在比较流行的前端存储数据库,找到了indexedDB,于是便对indexedDB做了一个较为深入的探索,此文就是记录探索过程的一些心得体会。
indexedDB为何物
在使用一个技术之前,先搞清楚它是什么,这对你的理解很重要,从DB就可以看出,它肯定是一个数据库,而说到数据库,有两种不同类型的数据库,就是关系型数据库和非关系型数据库,关系型数据库如Mysql、Oracle等将数据存储在表中,而非关系型数据库如Redis、MongoDB等将数据集作为个体对象存储。indexedDB就是一个非关系型数据库,它不需要你去写一些特定的sql语句来对数据库进行操作,因为它是nosql的,数据形式使用的是json,
indexedDB出现的意义
也许熟悉前端存储的会说,不是有了LocalStorage和Cookies吗?为什么还要推出indexedDB呢?其实对于在浏览器里存储数据,你可以使用cookies或local storage,但它们都是比较简单的技术,而IndexedDB提供了类似数据库风格的数据存储和使用方式。
首先说说Cookies,英文直接翻译过来就是小甜点,听起来很好吃,实际上并不是,每次HTTP接受和发送都会传递Cookies数据,它会占用额外的流量。例如,如果你有一个10KB的Cookies数据,发送10次请求,那么,总计就会有100KB的数据在网络上传输。Cookies只能是字符串。浏览器里存储Cookies的空间有限,很多用户禁止浏览器使用Cookies。所以,Cookies只能用来存储小量的非关键的数据。
其次说说LocalStorage,LocalStorage是用key-value键值模式存储数据,但跟IndexedDB不一样的是,它的数据并不是按对象形式存储。它存储的数据都是字符串形式。如果你想让LocalStorage存储对象,你需要借助JSON.stringify()能将对象变成字符串形式,再用JSON.parse()将字符串还原成对象。但如果要存储大量的复杂的数据,这并不是一种很好的方案。毕竟,localstorage就是专门为小数量数据设计的,所以它的api设计为同步的。而IndexedDB很适合存储大量数据,它的API是异步调用的。IndexedDB使用索引存储数据,各种数据库操作放在事务中执行。IndexedDB甚至还支持简单的数据类型。IndexedDB比localstorage强大得多,但它的API也相对复杂。对于简单的数据,你应该继续使用localstorage,但当你希望存储大量数据时,IndexedDB会明显的更适合,IndexedDB能提供你更为复杂的查询数据的方式。
indexedDB的特性
1.对象仓库
有了数据库后我们自然希望创建一个表用来存储数据,但indexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异。
任意值,但是没添加一条数据的时候需要指定键参数
任意值,但是没添加一条数据的时候需要指定键参数
keyGenerator
Javascript对象,如果对象中有keyPath指定的属性则不生成新的键值,如果没有自动生成递增键值,填充keyPath指定属性
如上图,有一个用于保存person的object Store,这个仓库的键就是person的ID值。
在indexedDB中,每一个对数据库操作是在一个事务的上下文中执行的。事务范围一次影响一个或多个object stores,你通过传入一个object store名字的数组到创建事务范围的函数来定义。例如:db.transaction(storeName, 'readwrite'),创建事务的第二个参数是事务模式。当请求一个事务时,必须决定是按照只读还是读写模式请求访问。
3. 基于请求
对indexedDB数据库的每次操作,描述为通过一个请求打开数据库,访问一个object store,再继续。IndexedDB API天生是基于请求的,这也是API异步本性指示。对于你在数据库执行的每次操作,你必须首先为这个操作创建一个请求。当请求完成,你可以响应由请求结果产生的事件和错误。
在IndexedDB大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求—响应的模式,所谓异步API是指并不是这条指令执行完毕,我们就可以使用request.result来获取indexedDB对象了,就像使用ajax一样,语句执行完并不代表已经获取到了对象,所以我们一般在其回调函数中处理。
indexedDB怎么玩
IndexedDB 鼓励使用的基本模式如下所示:
打开数据库并且开始一个事务。
创建一个 object store。
构建一个请求来执行一些数据库操作,像增加或提取数据等。
通过监听正确类型的 DOM 事件以等待操作完成。
在操作结果上进行一些操作(可以在 request 对象中找到)
接下来如果想要理解indexedDB具体怎么玩,最好的方法就是创建一个简单的web应用:把人的姓名、电话、地址存储在IndexedDB里。IndexedDB里提供了简单的增、删、改、查接口,界面如下:
1.打开数据库
a) &首先,你需要知道你的浏览器是否支持IndexedDB。
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
if(!indexedDB)
console.log("你的浏览器不支持IndexedDB");
b) &创建请求打开indexedDB:一旦你的浏览器支持IndexedDB,我们就可以打开它。你不能直接打开IndexedDB数据库。IndexedDB需要你创建一个请求来打开它。
var request = indexedDB.open(name, version);
第一个参数是数据库的名称,第二个参数是数据库的版本号。版本号可以在升级数据库时用来调整数据库结构和数据。但你增加数据库版本号时,会触发onupgradeneeded事件,这时可能会出现成功、失败和阻止事件三种情况:
request.onerror = function(e) {
console.log(e.currentTarget.error.message);
request.onsuccess = function(e) {
myDB.db = e.target.
console.log('成功打开DB');
request.onupgradeneeded = function(e) {
var db = e.target.
if (!db.objectStoreNames.contains('person')) {
console.log("我需要创建一个新的存储对象");
//如果表格不存在,创建一个新的表格(keyPath,主键 ; autoIncrement,是否自增),会返回一个对象(objectStore)
var objectStore = db.createObjectStore('person', {
keyPath: "id",
autoIncrement: true
//指定可以被索引的字段,unique字段是否唯一
objectStore.createIndex("name", "name", {
unique: false
objectStore.createIndex("phone", "phone", {
unique: false
console.log('数据库版本更改为: ' + version);
onupgradeneeded事件在第一次打开页面初始化数据库时会被调用,或在当有版本号变化时。所以,你应该在onupgradeneeded函数里创建你的存储数据。如果没有版本号变化,而且页面之前被打开过,你会获得一个onsuccess事件。
2. 添加数据
a) &首先需要创建一个事务,并要求具有读写权限
var transaction = db.transaction(storeName, 'readwrite');
b) &获取objectStore,再调用add方法添加数据
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onsuccess = function(e) {
data = e.target.
console.log(student.name);
3.删除数据
删除跟新增一样,需要创建事务,然后调用删除接口,通过key删除对象。
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
store.delete(key);
4.查找数据
a) &按key查找
开启事务,获取objectStore,调用往get()方法,往方法里传入对象的key值,取出相应的对象
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onsuccess = function(e) {
data = e.target.
console.log(student.name);
b) &使用索引查找
我们可以在创建object store的时候指明索引,使用object store的createIndex创建索引,方法有三个参数:索引名称、索引属性字段名、索引属性值是否唯一。
objectStore.createIndex("name", "name", {
unique: false
如上代码中,我们建好了name索引,就可以用该索引来进行查询了:
var transaction = db.transaction(storeName);
var store = transaction.objectStore(storeName);
var index = store.index(search_index);
index.get(value).onsuccess = function(e) {
data = e.target.
console.log(student.id);
c) &游标遍历数据
对数据库熟悉的同学很好理解游标的作用,有了数据库object store的游标,我们就可以利用游标遍历object store了。
var transaction = db.transaction(storeName);
var store = transaction.objectStore(storeName);
var request = store.openCursor();//打开游标
var dataList = new Array();
var i = 0;
request.onsuccess = function(e) {
var cursor = e.target.
if (cursor) {
console.log(cursor.key);
dataList[i] = cursor.
console.log(dataList[i].name);
cursor.continue();
data = dataL
4.更新对象
更新对象,首先要把它取出来,修改,然后再放回去。
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onsuccess = function(e) {
var data = e.target.
for (a in newData) {
//除了keypath之外
data.a = newData.a;
store.put(data);
5.关闭与删除数据库
关闭数据库可以直接调用数据库对象的close方法
function closeDB(db) {
db.close();
删除数据库使用数据库对象的deleteDatabase方法
function deleteDB(name) {
indexedDB.deleteDatabase(name);
以上就是indexedDB的一些基本概念以及使用,由于篇幅原因,还有一些更深入的细节没有介绍,比如indexedDB的游标结合索引,发挥其真正的优势,有兴趣的小伙伴可以继续深入研究,还有就是要注意浏览器的支持问题,IE9以及更早的版本并不支持,火狐和谷歌浏览器没有问题,推荐使用,文章如果纰漏或者不足,欢迎指正~博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)客户端持久化解决方案:indexedDB
indexedDB适合大量的结构化的数据存储;打开数据库和获取数据对象都是异步的;
需要开启事务,访问的objectStore都要是在开启的事务中。
数据库结构: db-&transaction-&objectStore-&data
Web SQL Database实际上已经被废弃,而HTML5支持的本地存储实际上变成了 Web Storage(Local Storage和Session Storage)与 IndexedDB。
Web Storage使用简单字符串键值对在本地存储数据,方便灵活,但是对于大量结构化数据存储力不从心,IndexedDB是为了能够在客户端存储大量的结构化数据,并且使用索引高效检索的API。
indexedDB最显著的特点: 异步API
在IndexedDB大部分操作(如:打开数据库和获取数据)并不是同步的,如:
var request=window.indexedDB.open('testDB');
这条指令并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象,而我们希望得到的DB对象在IDBOpenDBRequest.result属性中.
indexedDB的常用操作
创建/打开数据库
function openDB (name) {
var idbRequest=window.indexedDB.open(name);
idbRequest.onerror=function(e){
console.log('OPen Error!');
idbRequest.onsuccess=function(e){
var db=e.target.
console.log('db: %o', db);
openDB(dbName);
除了onerror和onsuccess,IDBOpenDBRequest还有一个类似回调函数句柄 onupgradeneeded。这个句柄在我们请求打开的数据库的版本号和已经存在的数据库版本号不一致的时候调用。
// indexedDB.open(dbName, version);
function openDB (name, version) {
version = version || 1;
//打开或创建数据库
var idbRequest = window.indexedDB.open(name, version);
idbRequest.onerror = function(e){
console.warn('error: %s', e.currentTarget.error.message);
idbRequest.onsuccess = function(e){
db = e.target. //这里才是 indexedDB对象
console.log('idbRequest === e.target: %o', idbRequest === e.target);
console.log('db: %o, idbRequest: %o', db, idbRequest);
// 注意: 只能请求&=当前数据库版本号的版本
大于当前版本号, 则触发 onupgradeneeded,
小于当前版本号,则触发 onerror
idbRequest.onupgradeneeded = function(e){
console.log('DB version change to ' + version);
var db = e.target.
console.log('onupgradeneeded: db-&', db);
删除数据库
window.indexedDB.deleteDatabase(dbName);
关闭数据库
db.onclose = function(){
//do sth..
db.close();
创建 objectStore
有了数据库后我们自然希望创建一个表用来存储数据,但indexedDB中没有表的概念,而是叫 objectStore ,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。
我们可以使用每条记录中的某个指定字段作为键值(keyPath 如: {keyPath: 'id'} ),也可以使用自动生成的递增数字作为键值(keyGenerator 如: {autoincrement: true} kk:很像mysql autoincrement字段),也可以不指定。
任意值,但是每添加一条数据的时候,需指定键参数
对象,eg: {keyPath: 'id'}
keyGenerator
任意值 eg: {autoincrement: true}
keyPath and KeyGenerator 都使用
对象,如果对象中有keyPath指定的属性则不生成新的键值,如果没有自动生成递增键值,填充keyPath指定的属性
在对新数据库做任何事情之前,需要开始一个事务。事务中需要指定该事务跨越哪些 objectStore.
事务具有三种模式:
只读:read,不能修改数据库数据,可以并发执行
读写:readwrite,可以进行读写操作
版本变更:verionchange
//打开一个事务,使用students 和teacher objectStore
var transaction=db.transaction([students','taecher']);
//获取students objectStore
var objectStore=transaction.objectStore('students');
//创建objectStore
db.createObjectStore(storeName, keyPath);
因为对新数据的操作都需要在transaction中进行,而transaction又要求指定objectStore,所以我们只能在创建数据库的时候初始化objectStore以供后面使用,这正是onupgradeneeded的一个重要作用。
function openDB (name,version) {
var version=version || 1;
var idbRequest=window.indexedDB.open(name,version);
idbRequest.onerror=function(e){
console.log(e.currentTarget.error.message);
idbRequest.onsuccess=function(e){
myDB.db=e.target.
idbRequest.onupgradeneeded=function(e){
var db=e.target.
if(!db.objectStoreNames.contains('students')){
//db.createObjectStore('students',{autoIncrement: true});//keyGenerator
db.createObjectStore('students',{keyPath:"id"});
console.log('DB version changed to '+version);
删除objectStore
db.deleteObjectStore(storeName); //注意:需在onupgradeneeded钩子中执行
保存数据到objectStore
function saveData (dbName, version, storeName, data) {
var idbRequest = indexedDB.open(dbName, version);
idbRequest.onsuccess = function (e) {
var db = idbRequest.
var transaction = db.transaction(storeName, 'readwrite');//需先创建事务
var store = transaction.objectStore(storeName); //访问事务中的objectStore
data.forEach(function (item) {
store.add(item);//保存数据
console.log('save data done..');
function getDataByKey(db,storeName,key){
var transaction=db.transaction(storeName,'readwrite');
var store=transaction.objectStore(storeName);
var dataRequest=store.get(key);
dataRequest.onsuccess=function(e){//异步的
var student=e.target.
console.log(student.name);
可以调用objectStore的put方法更新数据,会自动替换键值相同的记录,达到更新目的,没有相同的则添加。
function updateDataByKey(db,storeName,student){
var transaction=db.transaction(storeName,'readwrite');
var store=transaction.objectStore(storeName);
store.put(student);
function deleteDataByKey(db,storeName,key){
var transaction=db.transaction(storeName,'readwrite');
var store=transaction.objectStore(storeName);
store.delete(key);
function clearObjectStore(db,storeName){
var transaction=db.transaction(storeName,'readwrite');
var store=transaction.objectStore(storeName);
store.clear();
indexedDB的索引
熟悉数据库的同学都知道索引的一个好处就是可以迅速定位数据,提高搜索速度,在indexedDB中有两种索引,一种是自增长的int值,一种是keyPath:自己指定索引列,我们重点来看看keyPath方式的索引使用.
我们可以在db.createObjectStore(storeName, keyPath)时用 store.createIndex(indexName, key, opts)来指明索引。
function openDB (name,version) {
var version=version || 1;
var request=window.indexedDB.open(name,version);
request.onerror=function(e){
console.log(e.currentTarget.error.message);
request.onsuccess=function(e){
myDB.db=e.target.
request.onupgradeneeded=function(e){
var db=e.target.
if(!db.objectStoreNames.contains('students')){
var store=db.createObjectStore('students',{keyPath: 'id'});
//在students 上创建了两个索引
store.createIndex('nameIndex','name',{unique:true});
store.createIndex('ageIndex','age',{unique:false});
console.log('DB version changed to '+version);
利用索引快速获取数据,name的索引是唯一的没问题,但是对于age索引只会取到第一个匹配值,要想得到所有age符合条件的值就需要使用游标了
function getDataByIndex(db,storeName){
var transaction=db.transaction(storeName);
var store=transaction.objectStore(storeName);
var index = store.index("nameIndex");//获取索引
index.get('Byron').onsuccess=function(e){//通过索引获取数据
var student=e.target.
console.log(student.id);
在indexedDB中使用索引和游标是分不开的,对数据库熟悉的同学很好理解游标是什么东东,有了数据库objectStore的游标,我们就可以利用游标遍历objectStore了。
objectStore.openCursor(); //打开游标
function fetchStoreByCursor(db,storeName){
var transaction=db.transaction(storeName);
var store=transaction.objectStore(storeName);
var request=store.openCursor();
request.onsuccess=function(e){
var cursor=e.target.
if(cursor){
console.log(cursor.key);
var currentStudent=cursor.
console.log(currentStudent.name);
cursor.continue();
index与游标结合
要想获取age为26的student,可以结合游标使用索引
function getMultipleData(db,storeName){
var transaction=db.transaction(storeName);
var store=transaction.objectStore(storeName);
var index = store.index("ageIndex");
var request=index.openCursor(IDBKeyRange.only(26))
request.onsuccess=function(e){
var cursor=e.target.
if(cursor){
var student=cursor.
console.log(student.id);
cursor.continue();
这样我们可是使用索引打开一个游标,在成功的句柄内获得游标遍历age为26的student,也可以通过index.openKeyCursor()方法只获取每个对象的key值。
指定游标范围
index.openCursor()/index.openKeyCursor() 方法在不传递参数的时候会获取objectStore所有记录,像上面例子一样我们可以对搜索进行筛选
可以使用 IDBKeyRange 限制游标中值的范围,把它作为第一个参数传给 openCursor() 或是 openKeyCursor()
IDBKeyRange.only(value):只获取指定数据
IDBKeyRange.lowerBound(value,isOpen):获取最小是value的数据,第二个参数用来指示是否排除value值本身,也就是数学中的是否是开区间
IDBKeyRange.upperBound(value,isOpen):和上面类似,用于获取最大值是value的数据
IDBKeyRange.bound(value1,value2,isOpen1,isOpen2):不用解释了吧
// 获取名字首字母在B-E的student
function getMultipleData(db,storeName){
var transaction=db.transaction(storeName);
var store=transaction.objectStore(storeName);
var index = store.index("nameIndex");
var request=index.openCursor(IDBKeyRange.bound('B','F',false, true ));
request.onsuccess=function(e){
var cursor=e.target.
if(cursor){
var student=cursor.
console.log(student.name);
cursor.continue();
有了游标和索引才能真正发挥indexedDB威力
阅读(...) 评论()本文参与,欢迎正在阅读的你也加入,一起分享。|59 篇文章30 人订阅相关文章来自专栏299来自专栏126来自专栏228来自专栏327来自专栏309来自专栏325在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
我新建了一个数据库 demoDB ,我需要每次打开的时候,新建一张表(ObjectStore)来存储数据.但是indexedDB里想新建表,只能写在onupgradeneeded里,也就是说我必须把版本号增加1.现在已知可行的办法是 ,先打开demoDB,获取版本号,然后手动+1,再次打开,我觉得这种方法很蠢,有没有简单的解决办法?
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。}

我要回帖

更多关于 needed me 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信