Simple introduction

我们按照操作数据库的流程,来体验indexedDB的各种方法和对象。 code地址

链接数据库

if (!('indexedDB' in window)) return;
const DB = window.indexedDB.open('test','1');

这个方法接受两个参数,第一个参数是字符串,表示数据库的名字。如果指定的数据库不存在,就会新建数据库。第二个参数是整数,表示数据库的版本。如果省略,打开已有数据库时,默认为当前版本;新建数据库时,默认为1。

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

(1) error

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

DB.onerror = (err)=>{
    console.log('数据库打开失败')
  }

(2) success

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

let DB = null;
dbRequest.onsuccess = ()=>{
  DB = dbRequest.result;
  console.log('数据库打开成功')
}

可以通过request对象的result拿到数据库对象。 (3) upgradeneeded

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

let DB = null;
dbRequest.onupgradeneeded =  (event)=> {
  db = event.target.result;
  console.log('数据库升级')
}

新建数据库/新建对象仓库

新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于第一次新建数据库的时候,因为这时版本从无到有,会触发upgradeneeded,所以后续的操作主要在upgradeneeded事件的监听函数里面完成。

通常,新建数据库以后,第一件事是新建对象仓库(即新建表)。

dbRequest.onupgradeneeded =  (event)=> {
  db = event.target.result;
  console.log('数据库升级')
  const objectStore = db.createObjectStore('videos',{keyPath:'id'});
}

上面代码中,数据库新建成功以后,新增一张叫做videos的表格,主键是id。

更好的写法是先判断一下,这张表格是否存在,如果不存在再新建。

dbRequest.onupgradeneeded = (event) => {
   db = event.target.result;
   let objectStore;
   if (!db.objectStoreNames.contains('videos')) {
     objectStore = db.createObjectStore('videos', {
       keyPath: 'id'
     });
   }
 }

主键(key)是默认建立索引的属性。比如,数据记录是{ id: 1, name: 'ind' },那么id属性可以作为主键。主键也可以指定为下一层对象的属性,比如{ matches: { id: '239' } }matches.id也可以指定为主键。

如果数据记录里面没有合适作为主键的属性,那么可以让 IndexedDB 自动生成主键。

var objectStore = db.createObjectStore(
  'videos',
  { autoIncrement: true }
);

新建索引

新建对象仓库以后,下一步可以新建索引。

dbRequest.onupgradeneeded = (event) => {
    db = event.target.result;
    let objectStore;
    if (!db.objectStoreNames.contains('videos')) {
      objectStore = db.createObjectStore('videos', {
        keyPath: 'id'
      });
      objectStore.createIndex('channel_id', 'id', {
        unique: true
      })
    }
  }

上面代码中,IDBObject.createIndex()的三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。

新增数据

新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。

function add(){
  console.log('add')
  const transaction = DB.transaction(['videos'],'readwrite');
  const store = transaction.objectStore('videos');
  store.add({
    id: 'zLtKJ',
    res: {
      "result_code": 200,
      "data": {
        test:[]
      },
      "timestamp": 1552548880935
    }
  })
  request.onsuccess = (event)=>{
    console.log('write success')
  }
  request.onerror = (err)=>{
    console.log('write error')
    console.log(err)
  }
  transaction.oncomplete = ()=>{
    console.log('transaction store success')
  }
}

上面代码中,写入数据需要新建一个事务。新建时必须指定表格名称和操作模式("只读"或"读写")。表名可以是一个也可以是多个(数组)。

新建事务以后,通过IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。

写入操作是一个异步操作,通过监听连接对象的success事件和error事件,了解是否写入成功。

当有很多写入操作时,也可以监听事务的complete事件,来了解事务是否完成。

当要添加数据的对象存储空间中已经存在有相同键的数据时,使用add()方法添加数据会报错误,而put()方法则会对现有数据进行更新,所以add()方法一般用于初始化数据,而put()方法用于更新数据。

读取数据

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

function read(){
    const transaction = DB.transaction(['videos']);
    const store = transaction.objectStore('videos');
    const data = store.get('zLtKJ');
    data.onsuccess = (event)=>{
      if(event.target.result){
        console.log(event.target.result);
      }else{
        console.log('no data')
      }
    }
    data.onerror= (err)=>{
      console.log('get data error')
      console.log(err)
    }
  }

上面代码中,objectStore.get()方法用于读取数据,参数是主键的值。

遍历数据

遍历数据表格的所有记录,要使用指针对象 IDBCursor,同样通过事务完成。

function map(){
  const store = DB.transaction('videos').objectStore('videos');
  store.openCursor().onsuccess = (event)=>{
    const cursor = event.target.result;
    if (cursor) {
      console.log('Id: ' + cursor.key);
      console.log('value: ' + cursor.value);
      cursor.continue();
   } else {
     console.log('no more data');
   }
  }
}

上面代码中,新建指针对象的openCursor()方法是一个异步操作,所以要监听success事件。

更新数据

当如果存在key的数据,不能在add数据,会报错,只能更新数据。

function update(){
  const store = DB.transaction('videos','readwrite').objectStore('videos');
  const request = store.put({
    id:'zLtKJ',
    res:{
      data:{
        test:[],
        no:1
      }
    }
  });
  request.onsuccess = function (event) {
    console.log('update success');
  };

  request.onerror = function (event) {
    console.log('update fail');
  }
}

代码中,put()更新了id为zLtKJ的数据。

删除数据

function remove() {
  var request = DB.transaction(['videos'], 'readwrite')
    .objectStore('videos')
    .delete('zLtKJ');

  request.onsuccess = function (event) {
    console.log('delete success');
  };
}

索引

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

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

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

现在,就可以从name找到对应的数据记录了。

var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('webkong');

request.onsuccess = function (e) {
  var result = e.target.result;
  if (result) {
    // ...
  } else {
    // ...
  }
}

IndexedDB API是强大的,但对于简单的情况可能看起来太复杂。如果你更喜欢一个简单的API,可以使用一些第三方封装的库。 比如localForage, dexie.js, 和 ZangoDB等。

下面简单说一下localForage。

Last updated