IndexedDB:浏览器里内置的数据库

IndexedDB是HTML5规范里新出现的浏览器里内置的数据库。对于在浏览器里存储数据,你可以使用cookies或local storage,但它们都是比较简单的技术,而IndexedDB提供了类似数据库风格的数据存储和使用方式。存储在IndexedDB里的数据是永久保存,不像cookies那样只是临时的。IndexedDB里提供了查询数据的功能,在online和offline模式下都能使用。你可以用IndexedDB存储大型数据。

IndexedDB里数据以对象的形式存储,每个对象都有一个key值索引。IndexedDB里的操作都是事务性的。一种对象存储在一个objectStore里,objectStore就相当于关系数据库里的表。IndexedDB可以有很多objectStore,objectStore里可以有很多对象。每个对象可以用key值获取。

本地存储的类型

本地存储主要有以下几种:

  • Web Sql
  • IndexedDB
  • Local Storage
  • Session Storage
  • Cookies
  • Application Cache
     

项目需求

  • 离线存储读取数据
  • 允许用户对数据进行增删改操作
  • 数据存储在本地,不依赖后端
  • 数据支持索引查询
    由于 WebSQL 在标准上还存在争议,而 localStorage 实现数据分页、查询比较复杂,最终考虑使用了 IndexedDB 来满足需求。

IndexedDB 支持情况

3113457207-54978170af00f_articlex

IndexedDB 数据库的使用

定义数据库对象

1
2
3
4
5
var wxbDB = {
name : "wxb",
version: 1,
db : null
};

此处我们定义了一个数据库对象,包括name 数据库名称,version 数据库的版本,以及 db 数据对象。

 

数据库初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function initDB(dbObj) {
dbObj.version = dbObj.version || 1;
var request = indexedDB.open(dbObj.name, dbObj.version);
request.onerror = function (e) {
console.log(e.currentTarget.error.message);
};
request.onsuccess = function (e) {
dbObj.db = e.target.result;
};
request.onupgradeneeded = function (e) {
var thisDB = e.target.result;
if (!thisDB.objectStoreNames.contains("material")) {
var objStore = thisDB.createObjectStore("material", {keyPath: "id", autoIncrement: true});
objStore.createIndex("wxid", "wxid", {unique: true});
}
if (!thisDB.objectStoreNames.contains("account")) {
var objStore = thisDB.createObjectStore("account", {keyPath: "id", autoIncrement: true});
objStore.createIndex("wxid", "wxid", {unique: true});
objStore.createIndex("nickName", "nickName", {unique: false});
}
};
}

 

indexedDB.open 方法可以创建或者打开一个 IndexedDB,并返回 IDBOpenDBRequest 对象。

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

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

onupgradeneeded 被调用时,我们可以做一些建表、索引等操作。

有了数据库后我们自然希望创建一个表用来存储数据,但 indexedDB 中没有表的概念,而是 objectStore,一个数据库中可以包含多个 objectStoreobjectStore 是一个灵活的数据结构,可以存放多种类型数据。

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

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

关闭数据库

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

删除数据库

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

数据库表的 CURD

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

事务具有三种模式

  • 只读:read,不能修改数据库数据,可以并发执行
  • 读写:readwrite,可以进行读写操作
  • 版本变更:verionchange
  • 添加数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function addData(dbObj, tableName, data, cb) {
    var transaction = dbObj.db.transaction(tableName, 'readwrite');
    transaction.oncomplete = function () {
    console.log("transaction complete");
    };
    transaction.onerror = function (event) {
    console.dir(event)
    };

    var objectStore = transaction.objectStore(tableName);
    var request = objectStore.add(data);
    request.onsuccess = function (e) {
    if (cb) {
    cb({
    error: 0,
    data : data
    })
    }
    };
    request.onerror = function (e) {
    if (cb) {
    cb({
    error: 1
    })
    }
    }
    }

2458439816-54978c3f1a38e_articlex

2930526539-54978d3df3ad8_articlex

删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function deleteData(dbObj, tableName, id, cb) {
var transaction = dbObj.db.transaction(tableName, 'readwrite');
transaction.oncomplete = function () {
console.log("transaction complete");
};
transaction.onerror = function (event) {
console.dir(event)
};
var objectStore = transaction.objectStore(tableName);
var request = objectStore.delete(parseInt(id));
request.onsuccess = function (e) {
if (cb) {
cb({
error: 0,
data : parseInt(id)
})
}
};
request.onerror = function (e) {
if (cb) {
cb({
error: 1
})
}
}
}

查询数据

获取全部数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function getDataAll(dbObj, tableName, cb) {
var transaction = dbObj.db.transaction(tableName, 'readonly');
transaction.oncomplete = function () {
console.log("transaction complete");
};
transaction.onerror = function (event) {
console.dir(event)
};

var objectStore = transaction.objectStore(tableName);
var rowData = [];
objectStore.openCursor(IDBKeyRange.lowerBound(0)).onsuccess = function (event) {
var cursor = event.target.result;
if (!cursor && cb) {
cb({
error: 0,
data : rowData
});
return;
}
rowData.push(cursor.value);
cursor.continue();
};
}

471734684-54978db6a9a43_articlex

根据 id 获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function getDataById(dbObj, tableName, id, cb) {
var transaction = dbObj.db.transaction(tableName, 'readwrite');
transaction.oncomplete = function () {
console.log("transaction complete");
};
transaction.onerror = function (event) {
console.dir(event)
};

var objectStore = transaction.objectStore(tableName);
var request = objectStore.get(id);
request.onsuccess = function (e) {
if (cb) {
cb({
error: 0,
data : e.target.result
})
}
};
request.onerror = function (e) {
if (cb) {
cb({
error: 1
})
}
}
}

根据关键词索引获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function getDataBySearch(dbObj, tableName, keywords, cb) {
var transaction = dbObj.db.transaction(tableName, 'readwrite');
transaction.oncomplete = function () {
console.log("transaction complete");
};
transaction.onerror = function (event) {
console.dir(event)
};

var objectStore = transaction.objectStore(tableName);
var boundKeyRange = IDBKeyRange.only(keywords);
var rowData;
objectStore.index("nickName").openCursor(boundKeyRange).onsuccess = function (event) {
var cursor = event.target.result;
if (!cursor) {
if (cb) {
cb({
error: 0,
data : rowData
})
}
return;
}
rowData = cursor.value;
cursor.continue();
};
}

根据页码获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function getDataByPager(dbObj, tableName, start, end, cb) {
var transaction = dbObj.db.transaction(tableName, 'readwrite');
transaction.oncomplete = function () {
console.log("transaction complete");
};
transaction.onerror = function (event) {
console.dir(event)
};

var objectStore = transaction.objectStore(tableName);
var boundKeyRange = IDBKeyRange.bound(start, end, false, true);
var rowData = [];
objectStore.openCursor(boundKeyRange).onsuccess = function (event) {
var cursor = event.target.result;
if (!cursor && cb) {
cb({
error: 0,
data : rowData
});
return;
}
rowData.push(cursor.value);
cursor.continue();
};
}

 

更新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function updateData(dbObj, tableName, id, updateData, cb) {
var transaction = dbObj.db.transaction(tableName, 'readwrite');
transaction.oncomplete = function () {
console.log("transaction complete");
};
transaction.onerror = function (event) {
console.dir(event)
};

var objectStore = transaction.objectStore(tableName);
var request = objectStore.get(id);
request.onsuccess = function (e) {
var thisDB = e.target.result;
for (key in updateData) {
thisDB[key] = updateData[key];
}
objectStore.put(thisDB);
if (cb) {
cb({
error: 0,
data : thisDB
})
}
};
request.onerror = function (e) {
if (cb) {
cb({
error: 1
})
}
}
}

 

坚持原创技术分享,您的支持将鼓励我继续创作!