我们按照操作数据库的流程,来体验indexedDB的各种方法和对象。 code地址
链接数据库
Copy if ( ! ( 'indexedDB' in window)) return ;
const DB = window . indexedDB .open ( 'test' , '1' );
这个方法接受两个参数,第一个参数是字符串,表示数据库的名字。如果指定的数据库不存在,就会新建数据库。第二个参数是整数,表示数据库的版本。如果省略,打开已有数据库时,默认为当前版本;新建数据库时,默认为1。
indexedDB.open()
方法返回一个 IDBRequest
对象。这个对象通过三种事件error
、success
、upgradeneeded
,处理打开数据库的操作结果。
(1) error
error
事件表示打开数据库失败。
Copy DB.onerror = (err)=>{
console.log('数据库打开失败')
}
(2) success
success
事件表示打开数据库成功。
Copy let DB = null;
dbRequest.onsuccess = ()=>{
DB = dbRequest.result;
console.log('数据库打开成功')
}
可以通过request对象的result拿到数据库对象。 (3) upgradeneeded
如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件upgradeneeded
。
Copy let DB = null ;
dbRequest . onupgradeneeded = (event) => {
db = event . target .result;
console .log ( '数据库升级' )
}
新建数据库/新建对象仓库
新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于第一次新建数据库的时候,因为这时版本从无到有,会触发upgradeneeded,所以后续的操作主要在upgradeneeded事件的监听函数里面完成。
通常,新建数据库以后,第一件事是新建对象仓库
(即新建表)。
Copy dbRequest . onupgradeneeded = (event) => {
db = event . target .result;
console .log ( '数据库升级' )
const objectStore = db .createObjectStore ( 'videos' , {keyPath : 'id' });
}
上面代码中,数据库新建成功以后,新增一张叫做videos的表格,主键是id。
更好的写法是先判断一下,这张表格是否存在,如果不存在再新建。
Copy 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 自动生成主键。
Copy var objectStore = db.createObjectStore(
'videos',
{ autoIncrement: true }
);
新建索引
新建对象仓库以后,下一步可以新建索引。
Copy 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()的三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。
新增数据
新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。
Copy 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()方法用于更新数据。
读取数据
读取数据也是通过事务完成。
Copy 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,同样通过事务完成。
Copy 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数据,会报错,只能更新数据。
Copy 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的数据。
删除数据
Copy function remove() {
var request = DB.transaction(['videos'], 'readwrite')
.objectStore('videos')
.delete('zLtKJ');
request.onsuccess = function (event) {
console.log('delete success');
};
}
索引
索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。
假定新建表格的时候,对name字段建立了索引。
Copy objectStore.createIndex('name', 'name', { unique: false });
现在,就可以从name找到对应的数据记录了。
Copy 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。