目录

简介

对象接口

特点

键值对储存

异步

支持事务

同源限制

储存空间大

支持二进制储存

永久存在

使用

打开数据库(创建)

var request = window.indexedDB.open(databaseName, version)

error 事件

success 事件

upgradeneeded 事件

初始化数据库

IDBDatabase.createObjectStore(formName, { keyPath: ID })

IDBObjectStore.createIndex(indeName,property,{unique:boolean})

IDBObjectStore.add(obj)

事务操作

新增数据

IDBDatabase.transaction([formName],'readwrite').objectStore(formName).add(obj)

读取数据

IDBDatabase.transaction([formName]).objectStore(formName).get(primaryValue)

遍历数据

IDBDatabase.transaction([formName]).objectStore(formName).objectStore.openCursor().onsuccess = function (event) {}

更新数据

IDBDatabase.transaction([formName]).objectStore(formName).objectStore.put(obj) 

删除数据

IDBDatabase.transaction([formName]).objectStore(formName).objectStore.delete(primaryValue)

使用索引


简介

IndexedDB 是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

可以在网页中F12打开控制台后点击应用并在存储中查看。例如下图:

对象接口

IndexedDB 是一个比较复杂的 API,涉及不少概念。它把不同的实体,抽象成一个个对象接口。学习这个 API,就是学习它的各种对象接口。

下面是它的所有对象。

  • 操作请求:IDBRequest 对象(open函数返回的对象)
  • 数据库:IDBDatabase 对象(IDBRequest上的result属性)
  • 对象仓库:IDBObjectStore 对象(表名)
  • 索引: IDBIndex 对象(建立后可以通过get方法查找对应数据(未建立前只能通过主键查找))
  • 事务: IDBTransaction 对象(新建数据库后只能通过事务对象上的方法对数据库进行增删改查
  • 指针: IDBCursor 对象(用于遍历数据库
  • 主键集合:IDBKeyRange 对象

特点

键值对储存

IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。

异步

 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。

支持事务

IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

同源限制

 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

储存空间大

 IndexedDB 的储存空间比 LocalStorage (2.5MB~10MB)大得多,一般来说不少于 250MB,甚至没有上限。

支持二进制储存

IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

永久存在

和localStorage一样,只有手动删除时才会消失。

使用

打开数据库(创建)

var request = window.indexedDB.open(databaseName, version)

该方法返回一个 IDBRequest 对象。这个对象通过三种事件errorsuccessupgradeneeded,处理打开数据库的操作结果。

参数:databaseName是字符串,表示数据库的名字。如果指定的数据库不存在,就会新建数据库。version是整数,表示数据库的版本。如果省略,打开已有数据库时,不写默认为当前版本,如果版本低于已有数据库版本,会触发error事件;新建数据库时,默认为1

如图下面为一个IDBRequest对象,只有readyState状态为done时才会触发三种事件方法当为pending时,任何事件方法都不会触发。result属性对应的是IDBDatabase对象,该对象的name对应databaseName字符串,version对应。

error 事件

error事件表示打开数据库失败。

request.onerror = function (event) {
  console.log('数据库打开报错');
};

success 事件

success事件表示成功打开数据库。


var db;
request.onsuccess = function (event) {
  db = request.result;
  console.log('数据库打开成功');
};

这时,通过request对象的result属性拿到数据库对象。

upgradeneeded 事件

如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件upgradeneeded

创建数据库也是升级事件(版本从无到有),先触发升级事件再触发成功打开数据库事件


var db;
request.onupgradeneeded = function (event) {
  db = event.target.result;
}

这时通过事件对象的target.result属性,拿到数据库实例。

初始化数据库

新建对象仓库(即新建表)。一般在upgradeneeded事件里通过IDBDatabase对象的方法新建表,表中新建索引,最后放入数据。

IDBDatabase.createObjectStore(formName, { keyPath: ID })

新建表并设置主键,该方法返回IDBObjectStore对象,表示新建一个名为formName的表,其中主键名为ID。

参数:formName、ID为字符串。

下面代码:对这张表格是否存在进行了判断,如果不存在再新建。


request.onupgradeneeded = function (event) {
  db = event.target.result;
  var objectStore;
  if (!db.objectStoreNames.contains('person')) {
    objectStore = db.createObjectStore('person', { keyPath: 'id' });
  }
}

注意:主键在数据中是不允许重名

如果数据记录里面没有合适作为主键的属性,那么可以让 IndexedDB 自动生成主键。将函数中第二个参数改为{ autoIncrement: true },表示主键为一个递增的整数。

IDBObjectStore.createIndex(indeName,property,{unique:boolean})

新建索引。

参数:indexName为字符串表示数据库中的索引名称,property为字符串表示索引所在上的属性(对应新增对象数据时,取的属性值)、第三个参数是配置对象(说明该属性是否包含重复的值)。索引名称和索引所在的属性名一般相同。

request.onupgradeneeded = function(event) {
  db = event.target.result;
  var objectStore = db.createObjectStore('person', { keyPath: 'id' });
  objectStore.createIndex('name', 'name', { unique: false });
  objectStore.createIndex('email', 'email', { unique: true });
}

IDBObjectStore.add(obj)

新增一条数据,用于初始化数据。在外部新增数据要通过事务拿到对象仓库才能调用add方法。

参数:obj为一个对象,该对象的属性名和上一个方法中的property属性应该对应,这样才能添加进入值,且还要注意主键和一些属性unique为true的属性的值时不能重复的,如果重复在已有数据库添加数据时只会导致添加失败,但在新建数据库时即在onupgradeneeded事件使用中会导致新建数据库失败。

//onupgradeneeded中添加数据
var db
request.onupgradeneeded = function (event) {
        db = event.target.result;
        var objectStore = db.createObjectStore('person', { keyPath: 'id' });
        objectStore.createIndex('name1', 'name', { unique: false });
        objectStore.createIndex('email1', 'email', { unique: true });
        objectStore.add({id:'1',name:'2',email:'3'})
        objectStore.add({id:'2',name:'3',email:'4'})
}

事务操作

新增数据

这里的新增数据和初始化数据中的不同,不能直接拿到对象仓库。所以需要通过事务完成。

IDBDatabase.transaction([formName],'readwrite').objectStore(formName).add(obj)

写入数据需要新建一个事务。新建时必须指定表格名称和操作模式("只读"、"读写")。新建事务以后,通过IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。

参数:formName为字符串是需要插入数据库的表名,obj为一个对象,是插入的数据,该对象的属性名和索引中属性应该对应,

注意:写入操作是一个异步操作,通过监听连接对象的success事件和error事件,了解是否写入成功。每次都需要重新使用一遍事务即每次都需要使用重新使用transaction方法(即每次都要.transaction([formName],'readwrite').objectStore(formName).add(obj)用一遍)

下面封装了一个向指定数据库中添加数据的函数。databseName为需要打开的数据库名,formName为写入数据库的表名,dataArr为写入的数据,是一个数组,每位都是一个对象。

function add(databaseName,formName,dataArr) {
  let request = window.indexedDB.open(name)
  let db=request.result
  for(let i=0;i<dataArr.length;i++){
      let res = db.transaction([formName], 'readwrite')
        .objectStore(formName)
        .add(dataArr[i])
   }
   request.onsuccess = function (event) {
      console.log('数据写入成功')
   }
  request.onerror = function (event) {
      console.log('数据写入失败')
  }
}

读取数据

IDBDatabase.transaction([formName]).objectStore(formName).get(primaryValue)

读取数据也是同样也是通过事务完成。

参数:formName表示同上,primaryValue为字符串,会在数据库中查找到主键值为primaryValue的那一条数据返回到对象的result属性上。

下面是封装的函数打开指定数据库的指定表,并打印对应主键为primaryValue的那一条数据。

function read(databaseName,formName,primaryValue) {
   let request = window.indexedDB.open(name)
   let db=request.result
   let transaction = db.transaction([formName]);
   let objectStore = transaction.objectStore(formName);
   let res = objectStore.get(primaryValue);
   res.onerror = function(event) {
     console.log('事务失败');
   };
   res.onsuccess = function( event) {
      if (res.result) {
        console.log('id: ' + res.result.id);
        console.log('Name: ' + res.result.name);
        console.log('Email: ' + res.result.email);
      } else {
        console.log('未获得数据记录');
      }
   };
}

遍历数据

遍历数据表格的所有记录,要使用指针对象 IDBCursor。

IDBDatabase.transaction([formName]).objectStore(formName).objectStore.openCursor().onsuccess = function (event) {}

新建指针对象的openCursor()方法是一个异步操作,所以要监听success事件。会触发多次success事件,每次将数据绑定在event.target.result对象上。

下面封装方法查看指定数据库中指定表的所有数据。

function readAll(name,formName) {
   let request = window.indexedDB.open(name)
   let db=request.result
   let objectStore = db.transaction(formName).objectStore(formName);
   objectStore.openCursor().onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       console.log('Id: ' + cursor.key);
       console.log('Name: ' + cursor.value.name);
       console.log('Email: ' + cursor.value.email);
       cursor.continue();
    } else {
      console.log('没有更多数据了!');
    }
  };
}

更新数据

更新数据库中已有的数据

IDBDatabase.transaction([formName]).objectStore(formName).objectStore.put(obj) 

会查找obj.id(主键)值对应的一条数据,把该条数据中对应的值都更新一遍。

下面封装了更新指定数据库的指定表名的数据为obj。

function update(name,formName,obj) {
   let request = window.indexedDB.open(name)
   let db=request.result
   let request = db.transaction([formName], 'readwrite')
    .objectStore(formName)
    .put(obj);
  request.onsuccess = function (event) {
    console.log('数据更新成功');
  };
  request.onerror = function (event) {
    console.log('数据更新失败');
  }
}

删除数据

IDBDatabase.transaction([formName]).objectStore(formName).objectStore.delete(primaryValue)

会查找主键值对应为primaryValue的一条数据,把该条数据从数据库中删除。

下面封装了删除指定数据库的指定表名的主键值为primaryValue的一条数据。

function remove(name,formName,primaryValue) {
  let request = window.indexedDB.open(name)
  let db=request.result
  let res = db.transaction([formName], 'readwrite')
    .objectStore(formName)
    .delete(primaryValue);
  res.onsuccess = function (event) {
    console.log('数据删除成功');
  };
}

使用索引

索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。

假定新建表格的时候,对name字段建立了索引。

objectStore.createIndex('name', 'name', { unique: false });

之后可以从name找到对应的数据记录了。

例如下面代码打开数据库,读取person表中的name属性对应为李四的一条数据。在success事件中通过e.target.result查看对象。

let request = window.indexedDB.open(name)
let db=request.result
let transaction = db.transaction(['person'], 'readonly');
let store = transaction.objectStore('person');
let index = store.index('name');
let rest = index.get('李四');
res.onsuccess = function (e) {
  var result = e.target.result;
  if (result) {
    // ...
  } else {
    // ...
  }
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐