1.概念

IndexedDB是一种轻量级NoSQL(Not Only SQL,泛指非关系型)数据库,用来持久化大量客户端数据。

他可以让Web应用程序具有非常强大的查询能力,并且可以离线工作。

INdexedDB的数据操作直接使用JS脚本,不依赖SQL语句,操作返回均采用异步。

而localStorage和sessionStorage对象是采用同步技术实现少量客户端数据存储。

一个网站可能有一个或多个IndexedDB数据库,每个数据库必须有唯一的名称。

WebStorage(即localStorage和sessionStorage)可以用来存储键值对,然而它无法提供按顺序检索、高性能地按值查询或存储重复的键的功能。

2.使用IndexedDB

基本步骤

  1. 打开数据库并且开始一个事物
  2. 创建一个对象仓库(Object Storage)
  3. 创建一个请求来执行一些数据库操作(如增加或提取数据)
  4. 通过监听正确类型的DOM事件以等待操作完成
  5. 在操作结果上进行一些操作(可以在request对象中找到)

判断浏览器是否支持IndexedDB数据库

var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB;
//获得IndexedDB对象
if(window.indexedDB){
    alert("您的浏览器支持IndexedDB数据库");
}
else{
    alert("您的浏览器不支持IndexedDB数据库");
}

数据库创建与打开

使用window.indexedDB.open(DBName, DBVersion);来打开数据库(DBName为数据库名,DBVersion为数据库版本号)

var request = window.indexedDB.open("Mybooks", 2);

var request = window.indexedDB.open("Mybooks", 2);
			request.onerror = function(event){
				alert("数据库连接失败:" + event.target.errorCode);
			}
			request.onsuccess = function(event){
				db = event.target.result;
                //连接成功时获取数据库对象(也可以用request.result)
				alert("数据库连接成功!")
			}
			request.onupgradeneeded = function(event){
				//当此数据库创建前不存在时,进行初始化
				var db = request.result;
				var store = db.createObjectStore("books", {keyPath:"isbn"});
				var titleIndex = store.createIndex("by_title", "title", {unique:"true"});
				var anotherIndex = store.createIndex("by_author", "author");
				store.put({title:"计算机组成原理(修订版)", author:"陈彦亨", isbn:"111111111111"});
				store.put({title:"Java2实用教程", author:"陈彦亨", isbn:"22222222222"});
			}

在数据库连接时,open()方法返回一个IDBOpenRequest对象,调用函数定义在这个对象上(即request)

在连接到数据库后,request会监听三种状态

  • success:打开或创建数据库成功后绑定指定函数
  • error:打开或创建数据库失败后绑定指定函数
  • upgradeneeded:更新数据库后绑定指定函数

upgradeneeded状态是在indexedDB创建新的数据库时和indexedDB.open(DBName,DBVersion)DBVersion发生变化时才能监听得到的状态

创建与删除ObjectStore

ObjectStore(对象仓库、对象存储空间)是IndexedDB数据库的基础,在IndexedDB中并没有关系型数据库中的表,二十使用对象仓库(相当于关系型数据库的表)来存储数据。

db是已连接的数据库对象(var db=request.result)

request是IDBOpenDBRequest对象(var request = window.indexedDB.open(“myBooks”, 1))

1)createObjectStore()方法创建对象仓库

var store = db.createObjectStore(storeName, {keyPath:primaryKey, autoIncrement:true|false});

keyPath为键路径,作为ObjectStore的搜索关键字

var store = db.createObjectStore("books", {keyPath:"isbn});

2)deleteObjectStore()方法删除对象仓库

db.deleteObjectStore(objectStoreName)

db.deleteObjectStore("books");

3)createIndex()方法为对象仓库创建索引

var indexName = store.createIndex(intdex_name, index_key, {unique:true|false});

index_name是索引名称(例如"by_title"表示按标题建立索引),index_key是索引键值名称,{unique:true|false是可选项,表示是否唯一

4)objectStoreName属性检查对象仓库是否存在

objectStoreName属性返回一个DOMStringList对象,里面包含了当前数据库所有“对象仓库”的名称,可以使DOMStringList对象的contains方法,判断数据库是否包含某个“对象仓库”

if(!db.objectStoreNames.contains("books")){db.createObjectStore("books");}

使用事务

需要使用事务在对象存储上执行所有读取和写入操作

1)indexedDB中的事务模式

  • readonly:提供对某个对象的只读访问,在查询对象存储时使用
  • readwrite:提供对某个对象存储的读取和写入访问权
  • versionchange:提供读取和写入访问权来修改对象存储定义,或者创建一个新的对象存储

默认的事务模式为readonly,可以在任何给定时刻打开多个并发的readonly事务,但只能打开一个readwrite事务。因此只有在数据更新时才考虑使用readwrite事务。单独的(表示不能打开任何其他并发事务)versionchange事务操作一个数据库或者对象存储。可以在onupgradeneeded事件处理函数中使用version事务创建、修改或删除一个对象存储,或者将一个索引添加到对象存储。

2)创建事务的基本语法

var transaction = db.transaction(storeName, [transactionmode]);//storeName为对象仓库列表,transactionmode为事务模式

var objectStore = transaction.objectstore(storeName);

transaction()方法返回一个事务对象,objectStore()用于获取指定的对象仓库

var transaction1 = db.transaction("books", "readwrite");//为一个对象仓库创建一个读写事务
var transaction2 = db.transaction(["books", "press"], "readwrite");//为两个对象仓库创建一个读写事务
var objectStore = transaction1.objectStore("books");//获取books对象仓库

3)transaction()方法的事件类型

  • abort:事务中断
  • complete:事务完成
  • error:事务出错
var transaction = db.transaction("books", "readonly");
transaction.oncomplete = function(event){
	alert("数据保存成功");
}
transaction.onerror = function(event){
	console.log("Error", event.target.error.name);
}
transaction.onabort = function(event){
	alert("数据保存失败");
}

数据库的增删改查

1)存储数据准备

var booklists=[{title:"web前端开发技术", author:"陈先生", isbn:"9187302431695}, {title:“计算机组成原理”, author:"林某某“, isbn:"121233221321"}, {title:"Java2实用教程", author:"张某某", isbn:"1232145565667"}];

给books对象仓库定义三个对象存放在booklists数组里,其中没对{}中定义一个对象,每个对象之间用逗号分隔,准备写入到对象仓库中。

2)数据库的增加、更新、删除

objectStore.add(objectName);//添加数据,当关键字存在时数据不会添加
objectStore.put(objectName);//更新数据,当关键字存在时覆盖数据,不存在时会添加数据
objectStore.delete(value);//删除数据,删除指定的关键字对应数据
objectStore.clear();//清楚objectStore

3)数据库的数据读取

var request = objectStore.get(value);//查找数据,根据关键字查找指定的数据

//将已经定义的三个对象添加到对象仓库中
for(var i=0; i<booklists.length; i++){
	request = objectStore.add(booklists[i]);
	request.onerror = function(e){
		console.error("数据库中已有该对象,不能重复添加!");
	}
	request.onsuccess = function(e){
		console.log("对象已经成功存入对象仓库中");
	}
}

遍历数据openCursor()方法

使用对象仓库的openCursor()方法可以实现遍历数据。该方法可以获取游标对象,然后利用游标移动来实现数据遍历。openCursor()方法还可以接受第二个参数表示遍历方向,默认值为next,其他值为prev,nextunique和prevunique。后两个值表示如果遇到重复值,会自动跳过。

1)非索引搜索

var tx = db.transaction(["books"], "readonly");//创建事务对象
var objectStore = tx.objectStore("books");//利用事务对象获取指定的对象仓库
var cursor = objectStore.openCursor();//通过对象仓库打开游标
cursor.onsuccess = function(e){
    var result = e.target.result;//获取结果集
    if(result){
        console.log("key", result.key);//输出键名,如isbn
        console.log("data", result.value);//列出该对象所有属性和方法
        result.continue();//游标移到下一个数据对象上
    }
    else{
        console.log("没有数据可以遍历!");
    }
}
cursor.onerror = function(e){
    console.log("没有数据可以遍历!");
}

2)IDBKeyRange对象

通过索引可以读取指定范围内的数据。使用浏览器原生的IDBKeyRange对象能够生成指定范围的range对象。

如下为生成方法:

  • lowerBound()方法:指定范围的下限
  • upperBound()方法:指定范围的上限
  • bound()方法:指定范围的上下限
  • only()方法:指定范围中只有一个值

第二个参数带上true则表示不包含等于,不带上true则表示大于等于或小于等于

IDBKeyRange.upperbound(x, true);

IDBKeyRane.bound(x, y, true, false)//(x, y];

3)按索引查找数据

var index = objectStore.index(indexName);//indexName为已建立的索引名称(如title,name等)
var cursor = index.openCursor(range);//用IDBKeyRange生成范围range
cursor.addEventListener("success", function(event){
    var result = event.target.result;
    if(result){
        console.log(result.value);
        result.continue();
    }
}, false)
cursor.addEventListener("error", function(event){console.log("失败"), false});

Q.E.D.


   七岁几胆敢预言自己,操一艘战机