1.概念
IndexedDB是一种轻量级NoSQL(Not Only SQL,泛指非关系型)数据库,用来持久化大量客户端数据。
他可以让Web应用程序具有非常强大的查询能力,并且可以离线工作。
INdexedDB的数据操作直接使用JS脚本,不依赖SQL语句,操作返回均采用异步。
而localStorage和sessionStorage对象是采用同步技术实现少量客户端数据存储。
一个网站可能有一个或多个IndexedDB数据库,每个数据库必须有唯一的名称。
WebStorage(即localStorage和sessionStorage)可以用来存储键值对,然而它无法提供按顺序检索、高性能地按值查询或存储重复的键的功能。
2.使用IndexedDB
基本步骤
- 打开数据库并且开始一个事物
- 创建一个对象仓库(Object Storage)
- 创建一个请求来执行一些数据库操作(如增加或提取数据)
- 通过监听正确类型的DOM事件以等待操作完成
- 在操作结果上进行一些操作(可以在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}); ener("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});