HTML5本地存储——Web SQL Database提到过Web SQL Database实际上已经被废弃,而HTML5的支持的本地存储实际上变成了

Web Storage(Local Storage和Session Storage)与IndexedDB。Web Storage使用简单字符串键值对在本地存储数据,方便灵活,但是对于大量结构化数据存储力不从心,IndexedDB是为了能够在客户端存储大量的结 构化数据,并且使用索引高效检索的API。

异步API

在IndexedDB大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求——响应的模式,比如打开数据库的操作

  1. var request=window.indexedDB.open('testDB');

这条指令并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象,而我们希望得到的DB对象在其result属性中,

这条指令请求的响应是一个 IDBDatabase对象,这就是IndexedDB对象,

除了result,IDBOpenDBRequest接口定义了几个重要属性

  • onerror: 请求失败的回调函数句柄
  • onsuccess:请求成功的回调函数句柄
  • onupgradeneeded:请求数据库版本变化句柄

所谓异步API是指并不是这条指令执行完毕,我们就可以使用request.result来获取indexedDB对象了,就像使用ajax一样,语句执行完并不代表已经获取到了对象,所以我们一般在其回调函数中处理。

创建数据库

刚才的语句已经展示了如何打开一个indexedDB数据库,调用indexedDB.open方法就可以创建或者打开一个indexedDB。看一个完整的处理

  1. function openDB (name) {
  2. var request=window.indexedDB.open(name);
  3. request.onerror=function(e){
  4. console.log('OPen Error!');
  5. };
  6. request.onsuccess=function(e){
  7. myDB.db=e.target.result;
  8. };
  9. }
  10.  
  11. var myDB={
  12. name:'test',
  13. version:1,
  14. db:null
  15. };
  16. openDB(myDB.name);

代码中定义了一个myDB对象,在创建indexedDB request的成功毁掉函数中,把request获取的DB对象赋值给了myDB的db属性,这样就可以使用myDB.db来访问创建的indexedDB了。

version

我们注意到除了onerror和onsuccess,IDBOpenDBRequest还有一个类似回调函数句柄——onupgradeneeded。这个句柄在我们请求打开的数据库的版本号和已经存在的数据库版本号不一致的时候调用。

indexedDB.open()方法还有第二个可选参数,数据库版本号,数据库创建的时候默认版本号为1,当我们传入的版本号和数据库当前版本号 不一致的时候onupgradeneeded就会被调用,当然我们不能试图打开比当前数据库版本低的version,否则调用的就是onerror了,修 改一下刚才例子

  1. function openDB (name,version) {
  2. var version=version || 1;
  3. var request=window.indexedDB.open(name,version);
  4. request.onerror=function(e){
  5. console.log(e.currentTarget.error.message);
  6. };
  7. request.onsuccess=function(e){
  8. myDB.db=e.target.result;
  9. };
  10. request.onupgradeneeded=function(e){
  11. console.log('DB version changed to '+version);
  12. };
  13. }
  14.  
  15. var myDB={
  16. name:'test',
  17. version:3,
  18. db:null
  19. };
  20. openDB(myDB.name,myDB.version);

由于刚才已经创建了版本为1的数据库,打开版本为3的时候,会在控制台输出:DB version changed to 3

关闭与删除数据库

关闭数据库可以直接调用数据库对象的close方法

  1. function closeDB(db){
  2. db.close();
  3. }

删除数据库使用indexedDB对象的deleteDatabase方法

  1. function deleteDB(name){
  2. indexedDB.deleteDatabase(name);
  3. }

简单调用

  1. var myDB={
  2. name:'test',
  3. version:3,
  4. db:null
  5. };
  6. openDB(myDB.name,myDB.version);
  7. setTimeout(function(){
  8. closeDB(myDB.db);
  9. deleteDB(myDB.name);
  10. },500);

由于异步API愿意,不能保证能够在closeDB方法调用前获取db对象(实际上获取db对象也比执行一条语句慢得多),所以用了 setTimeout延迟了一下。当然我们注意到每个indexedDB实例都有onclose回调函数句柄,用以数据库关闭的时候处理,有兴趣同学可以 试试,原理很简单,不演示了。

object store

有了数据库后我们自然希望创建一个表用来存储数据,但indexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个 objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存 储的每条数据和一个键相关联。

我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异

键类型 存储数据
不使用 任意值,但是没添加一条数据的时候需要指定键参数
keyPath Javascript对象,对象必须有一属性作为键值
keyGenerator 任意值
都使用 Javascript对象,如果对象中有keyPath指定的属性则不生成新的键值,如果没有自动生成递增键值,填充keyPath指定属性

事务

在对新数据库做任何事情之前,需要开始一个事务。事务中需要指定该事务跨越哪些object store。

事务具有三种模式

  1. 只读:read,不能修改数据库数据,可以并发执行
  2. 读写:readwrite,可以进行读写操作
  3. 版本变更:verionchange
  1. var transaction=db.transaction([students','taecher']); //打开一个事务,使用students 和teacher object store
  2. var objectStore=transaction.objectStore('students'); //获取students object store

给object store添加数据

调用数据库实例的createObjectStore方法可以创建object store,方法有两个参数:store name和键类型。调用store的add方法添加数据。有了上面知识,我们可以向object store内添加数据了

keyPath

因为对新数据的操作都需要在transaction中进行,而transaction又要求指定object store,所以我们只能在创建数据库的时候初始化object store以供后面使用,这正是onupgradeneeded的一个重要作用,修改一下之前代码

  1. function openDB (name,version) {
  2. var version=version || 1;
  3. var request=window.indexedDB.open(name,version);
  4. request.onerror=function(e){
  5. console.log(e.currentTarget.error.message);
  6. };
  7. request.onsuccess=function(e){
  8. myDB.db=e.target.result;
  9. };
  10. request.onupgradeneeded=function(e){
  11. var db=e.target.result;
  12. if(!db.objectStoreNames.contains('students')){
  13. db.createObjectStore('students',{keyPath:"id"});
  14. }
  15. console.log('DB version changed to '+version);
  16. };
  17. }

这样在创建数据库的时候我们就为其添加了一个名为students的object store,准备一些数据以供添加

  1. var students=[{
  2. id:1001,
  3. name:"Byron",
  4. age:24
  5. },{
  6. id:1002,
  7. name:"Frank",
  8. age:30
  9. },{
  10. id:1003,
  11. name:"Aaron",
  12. age:26
  13. }];
  1. function addData(db,storeName){
  2. var transaction=db.transaction(storeName,'readwrite');
  3. var store=transaction.objectStore(storeName);
  4.  
  5. for(var i=0;i<students.length;i++){
  6. store.add(students[i]);
  7. }
  8. }
  9.  
  10. openDB(myDB.name,myDB.version);
  11. setTimeout(function(){
  12. addData(myDB.db,'students');
  13. },1000);

这样我们就在students object store里添加了三条记录,以id为键,在chrome控制台看看效果

keyGenerate

  1. function openDB (name,version) {
  2. var version=version || 1;
  3. var request=window.indexedDB.open(name,version);
  4. request.onerror=function(e){
  5. console.log(e.currentTarget.error.message);
  6. };
  7. request.onsuccess=function(e){
  8. myDB.db=e.target.result;
  9. };
  10. request.onupgradeneeded=function(e){
  11. var db=e.target.result;
  12. if(!db.objectStoreNames.contains('students')){
  13. db.createObjectStore('students',{autoIncrement: true});
  14. }
  15. console.log('DB version changed to '+version);
  16. };
  17. }

剩下的两种方式有兴趣同学可以自己摸索一下了

查找数据

可以调用object store的get方法通过键获取数据,以使用keyPath做键为例

  1. function getDataByKey(db,storeName,value){
  2. var transaction=db.transaction(storeName,'readwrite');
  3. var store=transaction.objectStore(storeName);
  4. var request=store.get(value);
  5. request.onsuccess=function(e){
  6. var student=e.target.result;
  7. console.log(student.name);
  8. };
  9. }

更新数据

可以调用object store的put方法更新数据,会自动替换键值相同的记录,达到更新目的,没有相同的则添加,以使用keyPath做键为例

  1. function updateDataByKey(db,storeName,value){
  2. var transaction=db.transaction(storeName,'readwrite');
  3. var store=transaction.objectStore(storeName);
  4. var request=store.get(value);
  5. request.onsuccess=function(e){
  6. var student=e.target.result;
  7. student.age=35;
  8. store.put(student);
  9. };
  10. }

删除数据及object store

调用object store的delete方法根据键值删除记录

  1. function deleteDataByKey(db,storeName,value){
  2. var transaction=db.transaction(storeName,'readwrite');
  3. var store=transaction.objectStore(storeName);
  4. store.delete(value);
  5. }

调用object store的clear方法可以清空object store

  1. function clearObjectStore(db,storeName){
  2. var transaction=db.transaction(storeName,'readwrite');
  3. var store=transaction.objectStore(storeName);
  4. store.clear();
  5. }

调用数据库实例的deleteObjectStore方法可以删除一个object store,这个就得在onupgradeneeded里面调用了

  1. if(db.objectStoreNames.contains('students')){
  2. db.deleteObjectStore('students');
  3. }

最后

这就是关于indexedDB的基本使用方式,很多同学看了会觉得很鸡肋,和我们正常自己定义个对象使用没什么区别,也就是能保存在本地罢了,这是 因为我们还没有介绍indexedDB之所以称为indexed的杀器——索引,这个才是让indexedDB大显神通的东西,下篇我们就来看看这个杀器。

HTML5本地存储——IndexedDB(一:基本使用)中介绍了关于IndexedDB的基本使用方法,很不过瘾,这篇我们来看看indexedDB的杀器——索引。

熟悉数据库的同学都知道索引的一个好处就是可以迅速定位数据,提高搜索速度,在indexedDB中有两种索引,一种是自增长的int值,一种是keyPath:自己指定索引列,我们重点来看看keyPath方式的索引使用.

创建索引

我们可以在创建object store的时候指明索引,使用object store的createIndex创建索引,方法有三个参数

  • 索引名称
  • 索引属性字段名
  • 索引属性值是否唯一
  1. function openDB (name,version) {
  2. var version=version || 1;
  3. var request=window.indexedDB.open(name,version);
  4. request.onerror=function(e){
  5. console.log(e.currentTarget.error.message);
  6. };
  7. request.onsuccess=function(e){
  8. myDB.db=e.target.result;
  9. };
  10. request.onupgradeneeded=function(e){
  11. var db=e.target.result;
  12. if(!db.objectStoreNames.contains('students')){
  13. var store=db.createObjectStore('students',{keyPath: 'id'});
  14. store.createIndex('nameIndex','name',{unique:true});
  15. store.createIndex('ageIndex','age',{unique:false});
  16. }
  17. console.log('DB version changed to '+version);
  18. };
  19. }

这样我们在students 上创建了两个索引

利用索引获取数据

  1. function getDataByIndex(db,storeName){
  2. var transaction=db.transaction(storeName);
  3. var store=transaction.objectStore(storeName);
  4. var index = store.index("nameIndex");
  5. index.get('Byron').onsuccess=function(e){
  6. var student=e.target.result;
  7. console.log(student.id);
  8. }
  9. }

这样我们可以利用索引快速获取数据,name的索引是唯一的没问题,但是对于age索引只会取到第一个匹配值,要想得到所有age符合条件的值就需要使用游标了

游标

在indexedDB中使用索引和游标是分不开的,对数据库熟悉的同学很好理解游标是什么东东,有了数据库object store的游标,我们就可以利用游标遍历object store了。

使用object store的openCursor()方法打开游标

  1. function fetchStoreByCursor(db,storeName){
  2. var transaction=db.transaction(storeName);
  3. var store=transaction.objectStore(storeName);
  4. var request=store.openCursor();
  5. request.onsuccess=function(e){
  6. var cursor=e.target.result;
  7. if(cursor){
  8. console.log(cursor.key);
  9. var currentStudent=cursor.value;
  10. console.log(currentStudent.name);
  11. cursor.continue();
  12. }
  13. };
  14. }

curson.contine()会使游标下移,知道没有数据返回undefined

index与游标结合

要想获取age为26的student,可以结合游标使用索引

  1. function getMultipleData(db,storeName){
  2. var transaction=db.transaction(storeName);
  3. var store=transaction.objectStore(storeName);
  4. var index = store.index("ageIndex");
  5. var request=index.openCursor(IDBKeyRange.only(26))
  6. request.onsuccess=function(e){
  7. var cursor=e.target.result;
  8. if(cursor){
  9. var student=cursor.value;
  10. console.log(student.id);
  11. cursor.continue();
  12. }
  13. }
  14. }

这样我们可是使用索引打开一个游标,参数下面会讲到,在成功的句柄内获得游标便利age为26的student,也可以通过index.openKeyCursor()方法只获取每个对象的key值。

指定游标范围

  1. index.openCursor()/index.openKeyCursor()方法在不传递参数的时候会获取object store所有记录,像上面例子一样我们可以对搜索进行筛选
  1. 可以使用key range 限制游标中值的范围,把它作为第一个参数传给 openCursor() 或是 openKeyCursor()
  1. IDBKeyRange.only(value):只获取指定数据
  1. IDBKeyRange.lowerBound(value,isOpen):获取最小是value的数据,第二个参数用来指示是否排除value值本身,也就是数学中的是否是开区间
  1. IDBKeyRange.upperBound(value,isOpen):和上面类似,用于获取最大值是value的数据
  1. IDBKeyRange.bound(value1,value2,isOpen1,isOpen2):不用解释了吧

获取名字首字母在B-E的student

  1. function getMultipleData(db,storeName){
  2. var transaction=db.transaction(storeName);
  3. var store=transaction.objectStore(storeName);
  4. var index = store.index("nameIndex");
  5. var request=index.openCursor(IDBKeyRange.bound('B','F',false,

true

  1. ));
  2. request.onsuccess=function(e){
  3. var cursor=e.target.result;
  4. if(cursor){
  5. var student=cursor.value;
  6. console.log(student.name);
  7. cursor.continue();
  8. }
  9. }
  10. }

完整示例

 

最后

有了游标和索引才能真正发挥indexedDB为例,是不是感觉比自定义对象强大方便了很多呢。

HTML5本地存储——IndexedDB的更多相关文章

  1. HTML5本地存储——IndexedDB(二:索引)

    在HTML5本地存储——IndexedDB(一:基本使用)中介绍了关于IndexedDB的基本使用方法,很不过瘾,这篇我们来看看indexedDB的杀器——索引. 熟悉数据库的同学都知道索引的一个好处 ...

  2. HTML5本地存储——IndexedDB二:索引

    HTML5本地存储——IndexedDB(二:索引)   在HTML5本地存储——IndexedDB(一:基本使用)中介绍了关于IndexedDB的基本使用方法,很不过瘾,这篇我们来看看indexed ...

  3. HTML5本地存储——IndexedDB(一:基本使用)

    在HTML5本地存储——Web SQL Database提到过Web SQL Database实际上已经被废弃,而HTML5的支持的本地存储实际上变成了 Web Storage(Local Stora ...

  4. HTML5本地存储——Web SQL Database与indexedDB

    虽然在HTML5 WebStorage介绍了html5本地存储的Local Storage和Session Storage,这两个是以键值对存储的解决方案,存储少量数据结构很有用,但是对于大量结构化数 ...

  5. HTML5本地存储——Web SQL Database

    在HTML5 WebStorage介绍了html5本地存储的Local Storage和Session Storage,这两个是以键值对存储的解决方案,存储少量数据结构很有用,但是对于大量结构化数据就 ...

  6. [转]HTML5本地存储——Web SQL Database

    在HTML5 WebStorage介绍了html5本地存储的Local Storage和Session Storage,这两个是以键值对存储的解决方案,存储少量数据结构很有用,但是对于大量结构化数据就 ...

  7. HTML5本地存储localStorage与sessionStorage

    在最近的项目中用到了html5的本地存储,下面总结一下. 1.html5几种存储形式 本地存储(localStorage && sessionStorage) 离线缓存(applica ...

  8. HTML5本地存储localStorage与sessionStorage详解

    前言 在最近的项目中用到了html5的本地存储,下面总结一下. 1.html5几种存储形式 本地存储(localStorage && sessionStorage) 离线缓存(appl ...

  9. HTML5本地存储(Local Storage) 的前世今生

    长久以来本地存储能力一直是桌面应用区别于Web应用的一个主要优势.对于桌面应用(或者原生应用),操作系统一般都提供了一个抽象层用来帮助应用程序保存其本地数据 例如(用户配置信息或者运行时状态等). 常 ...

随机推荐

  1. springboot手动配置数据源:

    @Configuration @EnableTransactionManagement @PropertySource(value = {"classpath:config/source.p ...

  2. Qless 相关知识

    Qless是一个基于redis的分布式任务架构.相关代码在 https://github.com/seomoz/qless 它是完全有lua实现的,依靠 redis 对lua的支持,http://ww ...

  3. poj 3070 Fibonacci 矩阵相乘

    Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7715   Accepted: 5474 Descrip ...

  4. Redis-跳跃表

    相当于Redis 中的 sorted set 跳跃表节点结构: typedef struct zskiplistNode { struct zskiplistNode *backward;  //后退 ...

  5. Dubbo 体验(一)

    最近新加入一个项目组,所使用的是Dubbo,采用的架构是分布式架构,数据库采用MySQL分片.之前也接触过一下,但为了能更好融入团队,所以找Dubbo官网看文档. 才发现Dubbo的官网已搬去apac ...

  6. Thymeleaf学习记录(6)--迭代及条件语法

    迭代: 条件选择: IF-THEN: (if) ? (then) IF-THEN-ELSE: (if) ? (then) : (else) 默认: (value) ?: (defaultvalue) ...

  7. tensorflow梯度下降

    import numpy as np import tensorflow as tf import matplotlib.pyplot as plt num_points = 1000 vectors ...

  8. JS 对html标签的属性的干预以及JS 对CSS 样式表属性的干预

      -任何标签的任何属性都可以修改! -HTML里是怎么写, JS就怎么写   以下是一段js 作用于 css 的 href的 代码   <link id="l1" rel= ...

  9. intellij idea下面安装热部署插件 JRebel 5.2

    之前一直是用的eclipse的JRebel,因为现在的公司用的是idea,于是尝试了在idea下面安装,把安装的过程中出现的问题记录下. 1.首先是在 idea里面install JRebel,Fil ...

  10. Zabbix 3.0 for Ubuntu 14.04 LTS 安装

    准备工作 apt-get install gettextapt-get install unzipapt-get install rar一.安装主程序 代码: 全选wget http://repo.z ...