在IndexedDB大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求——响应的模式,比如打开数据库的操作
var request=window.indexedDB.open('testDB');
这条指令并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象,而我们希望得到的DB对象在其result属性中,
result是一个 IDBDatabase对象,这就是IndexedDB对象,
继续是响应模式,那么request 可以绑定error success upgradeneeded(请求数据库版本变化句柄) 事件等。
var request=window.indexedDB.open('test',1.0);
request.οnerrοr=function(e){
console.debug(e);
}
var objectStore
request.onsuccess=function(e){
//console.log('a')
db=e.target.result;
console.log(db);
}
回调函数句柄——onupgradeneeded。这个句柄在我们请求打开的数据库的版本号和已经存在的数据库版本号不一致的时候调用。
indexedDB.open()方法还有第二个可选参数,数据库版本号,数据库创建的时候默认版本号为1,当我们传入的版本号和数据库当前版本号不一致的时候onupgradeneeded就会被调用,当然我们不能试图打开比当前数据库版本低的version,否则调用的就是onerror了,修改一下刚才例子
关闭与删除数据库
db.close();
indexedDB.deleteDatabase(name);
object store
ndexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。
我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异
类型 | 存储数据 |
不使用 | 任意值,但是没添加一条数据的时候需要指定键参数 |
keyPath | Javascript对象,对象必须有一属性作为键值 |
keyGenerator | 任意值 |
都使用 | Javascript对象,如果对象中有keyPath指定的属性则不生成新的键值,如果没有自动生成递增键值,填充keyPath指定属性 |
事务
在对新数据库做任何事情之前,需要开始一个事务。事务中需要指定该事务跨越哪些object store。
事务具有三种模式
- 只读:read,不能修改数据库数据,可以并发执行
- 读写:readwrite,可以进行读写操作
- 版本变更:verionchange
var transaction=db.transaction([students','taecher']); //打开一个事务,使用students 和teacher object store var objectStore=transaction.objectStore('students'); //获取students object store
给object store添加数据
调用数据库实例的createObjectStore方法可以创建object store,方法有两个参数:store name和键类型。调用store的add方法添加数据。有了上面知识,我们可以向object store内添加数据了keyPath
我们只能在创建数据库的时候初始化object store以供后面使用,这正是onupgradeneeded的一个重要作用
request.onupgradeneeded=function(e){
var db=e.target.result;
//删除表只有在版本不一至时才能删除
if (db.objectStoreNames.contains('students')) {
db.deleteObjectStore("students")
}
if(!db.objectStoreNames.contains('students')){
//keyPath用来指定表的主键名称,这样在添加时就需要指定keyPath属性名的值
db.createObjectStore('students',{keyPath:"id"});
}
console.log('DB version changed to '+version);
};
用contains判断是否有此store,没有就添加一个,指定keyPath为id
db.createObjectStore('user',{autoIncrement:true});
创建自增长,添加时不需要指定id了
添加数据
var transaction=db.transaction(storeName,'readwrite');
var store=transaction.objectStore(storeName);
store.add({id:1,nmae:'star',age:25})
var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName);store.add({id:1,nmae:'star',age:25})
查找数据
可以调用object store的get方法通过键获取数据,以使用keyPath做键为例
var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); var request=store.get(id); request.onsuccess=function(e){ var student=e.target.result; console.log(student.name); };
如果是集合是定义了keyPath的,那么get的值需要是字符串形的数字。
如果是自增长get的参数需要是数字。
更新数据
可以调用object store的put方法更新数据,会自动替换键值相同的记录,达到更新目的,没有相同的则添加,以使用keyPath做键为例
var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); var request=store.get(value); request.onsuccess=function(e){ var student=e.target.result; student.age=35; store.put(student); };
更新时用get查找数据,在回调内修改对象,然后用store.put()来更新对象。
对于指定了关键字的可以实现修改。
对于自增表它实现的是添加。
删除数据及object store
调用object store的delete方法根据键值删除记录var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); store.delete(value);用delete()来删除,和get一样,传递主键的用字符串数字,自增的用数字
调用object store的clear方法可以清空object store
var transaction=db.transaction(storeName,'readwrite'); var store=transaction.objectStore(storeName); store.clear();
调用数据库实例的deleteObjectStore方法可以删除一个object store
db.deleteObjectStore('students');
索引
熟悉数据库的同学都知道索引的一个好处就是可以迅速定位数据,提高搜索速度,在indexedDB中有两种索引,一种是自增长的int值,一种是keyPath:自己指定索引列,我们重点来看看keyPath方式的索引使用.
创建索引
我们可以在创建object store的时候指明索引,使用object store的createIndex创建索引,方法有三个参数
- 索引名称
- 索引属性字段名
- 索引属性值是否唯一
var store=db.createObjectStore('students',{keyPath: 'id'}); store.createIndex('nameIndex','name',{unique:true}); store.createIndex('ageIndex','age',{unique:false});
定义两个索引,一个是属性name 唯一和age不唯一。
利用索引获取数据
var transaction=db.transaction(['students'],'readwrite'); var objectStore=transaction.objectStore('students'); var myindex=objectStore.index('nameindex');//按nameindex 索引搜索 //根据name索引用get获取name=XX的记录 myindex.get($('#name').val()).onsuccess=function(e){ console.log(e.target.result); }索引只会返回第一个匹配的数据这样我们可以利用索引快速获取数据,name的索引是唯一的没问题,
但是对于age索引只会取到第一个匹配值,要想得到所有age符合条件的值就需要使用游标了
游标
在indexedDB中使用索引和游标是分不开的,对数据库熟悉的同学很好理解游标是什么东东,有了数据库object store的游标,我们就可以利用游标遍历object store了。
使用object store的openCursor()方法打开游标
var transaction=db.transaction(['students'],'readwrite'); var objectstore=transaction.objectStore('students'); /*openCursor()游标有二个参数,一个是数据查询对象,和游标方向 * IDBCursor.NEXT 顺序循环 * IDBCursor.NEXT_NO_DUPLICATE 顺序循环不重复 * IDBCursor.PREV 倒序循环 * IDBCursor.PREV_NO_DUPLICATE 倒序循环不重复 */ var req=objectstore.openCursor(null,IDBCursor.prev); /*监听成功函数,获取e.target.result。这是一个对象,内有下一个游标方法 */ req.onsuccess=function(e){ var r=e.target.result; console.log(e); if(r){ var listItem = document.createElement('li'); listItem.innerHTML = r.value.rollNo + ', ' + r.value.name; $("#result").append(listItem); r.continue(); }else{ console.log('getall error') } }
curson.contine()会使游标下移,知道没有数据返回undefined
游标的创建用openCursor()来创建。
在成功回调里通过result来获取游标对象。
r.value.XX来获取当前数据。
r.continue()指定下一条数据。
index与游标结合
var transaction=db.transaction(['students'],'readwrite'); var objectStore=transaction.objectStore('students'); var myindex=objectStore.index('nameindex');//按nameindex 索引搜索 //再用游标来获取列表 myindex.openCursor().onsuccess=function(e){ var cursor=e.target.result; if(cursor){ var listItem = document.createElement('li'); listItem.innerHTML = cursor.value.rollNo + ', ' + cursor.value.name; $("#result").append(listItem); cursor.continue(); }else{ console.log('getall error') } }可以用index指定索引,然后再用游标来获取数据。
获取指定name的所有数据
var transaction=db.transaction(['students'],'readwrite'); var objectStore=transaction.objectStore('students'); var myindex=objectStore.index('nameindex');//按nameindex 索引搜索 /*IDBKeyRange.only(value):只获取指定数据 *IDBKeyRange.lowerBound(value,isOpen):获取最小是value的数据,第二个参数用来指示是否排除value值本身,也就是数学中的是否是开区间 * IDBKeyRange.upperBound(value,isOpen):和上面类似,用于获取最大值是value的数据 * IDBKeyRange.bound('b','f',isOpen1,isOpen2) 获取首字母在b-f的记录 */ //获取name=XX的所有记录 var req=myindex.openCursor(IDBKeyRange.only($('#name').val())).onsuccess=function(e){ var cursor=e.target.result; if(cursor){ var student=cursor.value; console.log(student); cursor.continue(); } }
在游标调用时可以指定参数:IDBKeyRange.only()
来设置搜索索引下指定值的游标。