基本概念
特性
- 可以存储大量数据(>250MB,2G+)
- 可以离线查询(离线应用)
- 可以持久化的存储数据(长久保留)
- 可以在Web Worker中使用(多线程)
- 基于JS的面向对象的数据库
- 事务模式的数据库
- 使用键值对存储数据
- 异步API和事件通知
- 创建索引
- 使用游标遍历数据集合
- 存储结构化克隆算法支持的对象
- 浏览器的同源策略
术语
- 数据库
- 版本号
- 对象仓库
- 事务
- 索引
- 请求
- 键和值
- 键路径
- 键生成器
- 外键
- 作用域和范围
- 只读和读写
- 游标
- 键范围
基本模式
- 打开数据库
- 创建对象仓库
- 启动事务,请求数据库操作
- 监听请求事件,等待操作完成
- 在操作结果上进行一些操作
对象接口
- IDBOpenDBRequest 打开数据库的请求
- IDBDatabase 数据库连接的实例
- IDBTransaction 事务
- IDBObjectStore 对象仓库
- IDBIndex 索引
- IDBCursor 游标 (IDBCursorWithValue)
- IDBKeyRange 键范围
- IDBRequest 处理数据库的请求
具体操作
数据库
新建、升级、连接数据库
indexedDB.open(name: string, version?: number): IDBOpenDBRequest
const openReq = indexedDB.open('test') // version 默认为 1
openReq.onupgradeneeded = (e) => {
console.log('open onupgradeneeded', e) // e: IDBVersionChangeEvent
// 创建(删除)对象仓库,以及创建(删除)索引
}
openReq.onsuccess = (e) => {
console.log('open onsuccess', e) // e: Event
// 获取数据库对象实例,为数据的增删改查做准备
const db = openReq.result
}
关闭数据库
IDBDatabase.close(): void
const openReq = indexedDB.open('test')
openReq.onsuccess = () => {
const db = openReq.result
// ...
db.close()
}
删除数据库
indexedDB.deleteDatabase(name: string): IDBOpenDBRequest
const delReq = indexedDB.deleteDatabase('test')
delReq.onsuccess = (e) => {
console.log('del onsuccess', e) // e: IDBVersionChangeEvent
}
对象仓库
新建对象仓库
IDBDatabase.createObjectStore(name: string, optionalParameters?: IDBObjectStoreParameters): IDBObjectStore
| 键路径(keyPath) | 键生成器(autoIncrement) | 描述 |
|---|---|---|
| No | No | 这种对象存储空间可以持有任意类型的值,甚至是像数字和字符串这种基本数据类型的值。每当我们想要增加一个新值的时候,必须提供一个单独的键参数。 |
| Yes | No | 这种对象存储空间只能持有 JavaScript 对象。这些对象必须具有一个和 key path 同名的属性。 |
| No | Yes | 这种对象存储空间可以持有任意类型的值。键会为我们自动生成,或者如果你想要使用一个特定键的话你可以提供一个单独的键参数。 |
| Yes | Yes | 这种对象存储空间只能持有 JavaScript 对象。通常一个键被生成的同时,生成的键的值被存储在对象中的一个和 key path 同名的属性中。然而,如果这样的一个属性已经存在的话,这个属性的值被用作键而不会生成一个新的键。 |
使用指定键值
- 创建并访问对象仓库
const openReq = indexedDB.open('test', 2)
openReq.onupgradeneeded = () => {
const db = openReq.result
const store = db.createObjectStore('users_out') // key 外键
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_out']) // mode 默认为 'readonly'
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_out')
console.log('store', store.name)
}
- 新增数据
const openReq = indexedDB.open('test', 2)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_out'], 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_out')
const req = store.add({ name: '小王' }, '1') // Key: 1; Value: { name: "小王" }
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
}
使用键生成器
const openReq = indexedDB.open('test', 3)
openReq.onupgradeneeded = () => {
const db = openReq.result
db.createObjectStore('users_gen', { autoIncrement: true })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_gen'], 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_gen')
const req = store.add({ name: '小王' }) // Key: 1; Value: { name: "小王" }
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
store.add({ name: '小王' }) // Key: 2; Value: { name: "小王" }
}
使用键路径(属性)
const openReq = indexedDB.open('test', 4)
openReq.onupgradeneeded = () => {
const db = openReq.result
db.createObjectStore('users_id', { keyPath: 'id' })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_id'], 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_id')
const req = store.add({ id: 'xw', name: '小王' }) // Key(key path: "id"): "xw"; Value: { id: "xw", name: "小王" }
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
}
使用键路径(点号连接)
const openReq = indexedDB.open('test', 5)
openReq.onupgradeneeded = () => {
const db = openReq.result
db.createObjectStore('users_point', { keyPath: 'user.id' })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_point'], 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_point')
const req = store.add({ user: { id: '11', name: '小王' } }) // Key: "11"; Value: { user: {id: "11", name: "小王"} }
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
store.add({ user: { id: '22', name: '小王' } }) // Key: "22"; Value: { user: {id: "22", name: "小王"} }
}
使用键路径(数组)
const openReq = indexedDB.open('test', 6)
openReq.onupgradeneeded = () => {
const db = openReq.result
db.createObjectStore('users_arr', { keyPath: ['id', 'name'] })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_arr'], 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_arr')
const req = store.add({ id: '11', name: '小王' }) // Key: ["11", "小王"]; Value: {id: "11", name: "小王"}
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
store.add({ id: '11', name: '小张' }) // Key: ["11", "小张"]; Value: {id: "11", name: "小张"}
store.add({ id: '22', name: '小王' }) // Key: ["22", "小王"];; Value: {id: "22", name: "小王"}
}
同时使用键路径和键生成器
const openReq = indexedDB.open('test', 7)
openReq.onupgradeneeded = () => {
const db = openReq.result
db.createObjectStore('users_mix2', { keyPath: 'id', autoIncrement: true })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_mix2'], 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_mix2')
const req = store.add({ id: '123', name: '小王' }) // Key: "123"; Value: {id: "123", name: "小王"}
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
store.add({ name: '小王' }) // Key: 1; Value: {id: 1, name: "小王"}
store.add({ name: '小王' }) // Key: 2; Value: {id: 2, name: "小王"}
}
新建仓库的同时添加数据
const openReq = indexedDB.open('test', 8)
openReq.onupgradeneeded = () => {
const db = openReq.result
const store = db.createObjectStore('users_direct', { autoIncrement: true })
const tx = store.transaction
tx.oncomplete = () => {
const tx2 = db.transaction(['users_direct'], 'readwrite')
tx2.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx2.onerror = (e) => {
console.log('tx onerror', e)
}
const store2 = tx2.objectStore('users_direct')
const req = store2.add('小王') // Key: 1; Value: "小王"
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
store2.add('小王') // Key: 2; Value: "小王"
store2.add('小张') // Key: 3; Value: "小张"
}
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction(['users_direct'])
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_direct')
const req = store.count() // 3
req.onsuccess = () => {
console.log('req success count', req.result)
}
req.onerror = (e) => {
console.log('req error', e)
}
}
清空对象仓库
IDBObjectStore.clear(): IDBRequest<undefined>
const openReq = indexedDB.open('test', 9)
openReq.onupgradeneeded = () => {
const db = openReq.result
const store = db.createObjectStore('users_clear')
const tx = store.transaction
tx.oncomplete = () => {
const tx2 = db.transaction(['users_clear'], 'readwrite')
tx2.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx2.onerror = (e) => {
console.log('tx onerror', e)
}
const store2 = tx2.objectStore('users_clear')
const req = store2.add('小王', 'x') // Key: "x"; Value: "小王"
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
}
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('users_clear', 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('users_clear')
const req = store.clear()
req.onsuccess = (e) => {
console.log('clear success', e)
}
req.onerror = () => {
console.log('clear error', e)
}
}
删除对象仓库
IDBDatabase.deleteObjectStore(name: string): void
const openReq = indexedDB.open('test', 10)
openReq.onupgradeneeded = () => {
const db = openReq.result
db.deleteObjectStore('users_clear')
}
openReq.onsuccess = () => {
console.log('delete success')
}
对象仓库是否已经存在
IDBDatabase.objectStoreNames.contains(string: string): boolean
const openReq = indexedDB.open('test', 11)
openReq.onupgradeneeded = () => {
console.log('open onupgradeneeded')
const db = openReq.result
console.log('objectStoreNames', db.objectStoreNames)
console.log('objectStoreNames contains users_gen', db.objectStoreNames.contains('users_gen'))
}
openReq.onsuccess = () => {
console.log('open onsuccess')
const db = openReq.result
console.log('objectStoreNames', db.objectStoreNames)
console.log('objectStoreNames contains users_arr', db.objectStoreNames.contains('users_arr'))
}
索引
新建索引
IDBObjectStore.createIndex(name: string, keyPath: string | string[], options?: IDBIndexParameters): IDBIndex
const openReq = indexedDB.open('test', 12)
openReq.onupgradeneeded = () => {
const db = openReq.result
const store = db.createObjectStore('user_idx', { keyPath: 'id' })
const index = store.createIndex('name', 'name', { unique: false })
console.log(index.name, index.keyPath, index.multiEntry, index.unique, index.objectStore)
store.createIndex('age', 'age', { unique: false, multiEntry: true })
store.createIndex('name_age', ['name', 'age'], { unique: true, multiEntry: false })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_idx', 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('user_idx')
const req = store.add({ id: '123', name: '小王', age: 20 })
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
store.add({ id: '234', name: '小王', age: 22 })
/**
* Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: "234"; Value: {id: "234", name: "小王", age: 22}
*
* Index - name:
* Key: "小王"; Primary Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: "小王"; Primary Key: "234"; Value: {id: "234", name: "小王", age: 22}
*
* Index - age:
* Key: 20; Primary Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: 22; Primary Key: "234"; Value: {id: "234", name: "小王", age: 22}
*
* Index - name_age:
* Key: ["小王", 20]; Primary Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: ["小王", 22]; Primary Key: "234"; Value: {id: "234", name: "小王", age: 22}
*/
}
删除索引
IDBObjectStore.deleteIndex(name: string): void
const openReq = indexedDB.open('test', 13)
openReq.onupgradeneeded = () => {
console.log('openReq', openReq.transaction)
const tx = openReq.transaction // 升级事务(允许执行任何操作,包括删除和创建对象存储和索引的操作)
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('user_idx')
store.deleteIndex('age')
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_idx', 'readwrite')
tx.oncomplete = (e) => {
console.log('tx oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx onerror', e)
}
const store = tx.objectStore('user_idx')
const req = store.add({ id: '345', name: '小王', age: 23 })
req.onsuccess = () => {
console.log('store onsuccess', req.result)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
/**
* Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: "234"; Value: {id: "234", name: "小王", age: 22}
* Key: "345"; Value: {id: "345", name: "小王", age: 23}
*
* Index - name:
* Key: "小王"; Primary Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: "小王"; Primary Key: "234"; Value: {id: "234", name: "小王", age: 22}
* Key: "小王"; Primary Key: "345"; Value: {id: "345", name: "小王", age: 23}
*
* Index - name_age:
* Key: ["小王", 20]; Primary Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: ["小王", 22]; Primary Key: "234"; Value: {id: "234", name: "小王", age: 22}
* Key: ["小王", 23]; Primary Key: "345"; Value: {id: "345", name: "小王", age: 23}
*/
}
更新索引
IDBOpenDBRequest.transaction.objectStore(name: string): IDBObjectStore
const openReq = indexedDB.open('test', 14)
openReq.onupgradeneeded = () => {
const tx = openReq.transaction // 升级事务
tx.oncomplete = (e) => {
console.log('tx1 oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx1 onerror', e)
}
const store = tx.objectStore('user_idx')
store.deleteIndex('name')
store.deleteIndex('name_age') // unique: true -> false
store.createIndex('name_age', ['name', 'age'], { unique: false, multiEntry: false })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_idx', 'readwrite')
tx.oncomplete = (e) => {
console.log('tx2 oncomplete', e)
}
tx.onerror = (e) => {
console.log('tx2 onerror', e)
}
const store = tx.objectStore('user_idx')
const req = store.add({ id: '456', name: '小王', age: 23 })
req.onsuccess = (e) => {
console.log('store onsuccess', e)
}
req.onerror = (e) => {
console.log('store onerror', e)
}
/**
* Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: "234"; Value: {id: "234", name: "小王", age: 22}
* Key: "345"; Value: {id: "345", name: "小王", age: 23}
* Key: "456"; Value: {id: "456", name: "小王", age: 23}
*
* Index - name_age:
* Key: ["小王", 20]; Primary Key: "123"; Value: {id: "123", name: "小王", age: 20}
* Key: ["小王", 22]; Primary Key: "234"; Value: {id: "234", name: "小王", age: 22}
* Key: ["小王", 23]; Primary Key: "345"; Value: {id: "345", name: "小王", age: 23}
* Key: ["小王", 23]; Primary Key: "456"; Value: {id: "456", name: "小王", age: 23}
*/
}
数据操作
新建仓库和测试数据
IDBObjectStore.add(value: any, key?: IDBValidKey): IDBRequest<IDBValidKey>
const openReq = indexedDB.open('test', 15)
openReq.onupgradeneeded = () => {
const db = openReq.result
// userInfo 至少包含 name, phone, addr 三个属性(id 属性没有可以自动生成)
const store = db.createObjectStore('user_info', { keyPath: 'id', autoIncrement: true })
store.createIndex('name', 'name', { unique: false })
store.createIndex('phone', 'phone', { unique: true })
store.createIndex('name_addr', ['name', 'addr'], { unique: true, multiEntry: false })
}
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readwrite')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const userInfos = [
{ name: '小王', phone: '13122223333', addr: 'A', id: '1234' },
{ name: '小王', phone: '13122224444', addr: 'B', id: '5678' },
{ name: '小张', phone: '13122225555', addr: 'A' },
{ name: '小吴', phone: '13122226666', addr: 'C' }
]
userInfos.forEach(user => {
const req = store.add(user)
req.onsuccess = () => {
console.log('add result', req.result)
}
})
}
使用主键检索
查询记录数
IDBObjectStore.count(key?: IDBValidKey | IDBKeyRange): IDBRequest<number>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.count()
req.onsuccess = () => {
console.log('get count', req.result) // 4
}
}
查询数据
IDBObjectStore.get(query: IDBValidKey | IDBKeyRange): IDBRequest<any | undefined>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.get(2)
req.onsuccess = () => {
console.log('get result', req.result) // {name: "小吴", phone: "13122226666", addr: "C", id: 2}
}
}
- 使用不存在的主键查询
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.get(3)
req.onsuccess = () => {
console.log('get result', req.result) // undefined
}
}
查询所有数据
IDBObjectStore.getAll(query?: IDBValidKey | IDBKeyRange | null, count?: number): IDBRequest<any[]>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.getAll()
req.onsuccess = () => {
console.log('get result', req.result)
// [
// { name: "小张", phone: "13122225555", addr: "A", id: 1 },
// { name: "小吴", phone: "13122226666", addr: "C", id: 2 },
// { name: "小王", phone: "13122223333", addr: "A", id: "1234" },
// { name: "小王", phone: "13122224444", addr: "B", id: "5678" }
// ]
}
}
- 查询指定范围内的所有数据
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const keyRange = IDBKeyRange.bound(1, 2)
const req = store.getAll(keyRange)
req.onsuccess = () => {
console.log('get result', req.result)
// [
// { name: "小张", phone: "13122225555", addr: "A", id: 1 },
// { name: "小吴", phone: "13122226666", addr: "C", id: 2 }
// ]
}
}
查询主键
IDBObjectStore.getKey(query: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey | undefined>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.getKey(2)
req.onsuccess = () => {
console.log('get result', req.result) // 2
}
}
查询所有主键
IDBObjectStore.getAllKeys(query?: IDBValidKey | IDBKeyRange | null, count?: number): IDBRequest<IDBValidKey[]>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.getAllKeys()
req.onsuccess = () => {
console.log('get result', req.result) // [1, 2, "1234", "5678"]
}
}
- 查询指定范围内的所有键
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const keyRange = IDBKeyRange.bound(1, 2)
const req = store.getAllKeys(keyRange)
req.onsuccess = () => {
console.log('get result', req.result) // [1, 2]
}
}
更新数据
IDBObjectStore.put(value: any, key?: IDBValidKey): IDBRequest<IDBValidKey>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readwrite')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const getReq = store.get(2)
getReq.onsuccess = () => {
const data = getReq.result
console.log('get result', data) // {name: "小吴", phone: "13122226666", addr: "C", id: 2}
data.phone = '13122227777'
data.addr = 'D'
const putReq = store.put(data) // 更新数据
putReq.onsuccess = () => {
console.log('put result', putReq.result) // 2
}
putReq.onerror = (e) => {
console.log('put error', e)
}
}
const putReq = store.put({ name: "小王", phone: "13122228888", addr: "D" }) // 新增数据
putReq.onsuccess = () => {
console.log('put result', putReq.result) // 3
}
putReq.onerror = (e) => {
console.log('put error', e)
}
}
删除数据
IDBObjectStore.delete(key: IDBValidKey | IDBKeyRange): IDBRequest<undefined>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readwrite')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.delete(1)
req.onsuccess = () => {
console.log('del result', req.result) // undefined
}
}
使用索引检索
IDBObjectStore.index(name: string): IDBIndex
查询记录数
IDBIndex.count(key?: IDBValidKey | IDBKeyRange): IDBRequest<number>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
console.log(store.indexNames) // {0: "name", 1: "name_addr", 2: "phone", length: 3}
const index = store.index('name')
const req = index.count('小王')
req.onsuccess = () => {
console.log('get result', req.result) // 3
}
}
查询数据
IDBIndex.get(key: IDBValidKey | IDBKeyRange): IDBRequest<any | undefined>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.get('小王')
req.onsuccess = () => {
console.log('get result', req.result) // {name: "小王", phone: "13122228888", addr: "D", id: 3}
}
}
查询所有数据
IDBIndex.getAll(query?: IDBValidKey | IDBKeyRange | null, count?: number): IDBRequest<any[]>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.getAll('小王')
req.onsuccess = () => {
console.log('get result', req.result)
// [
// { name: "小王", phone: "13122228888", addr: "D", id: 3 },
// { name: "小王", phone: "13122223333", addr: "A", id: "1234" },
// { name: "小王", phone: "13122224444", addr: "B", id: "5678" }
// ]
}
}
查询索引键
IDBIndex.getKey(key: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey | undefined>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.getKey('小王')
req.onsuccess = () => {
console.log('get result', req.result) // 3
}
}
查询所有索引键
IDBIndex.getAllKeys(query?: IDBValidKey | IDBKeyRange | null, count?: number): IDBRequest<IDBValidKey[]>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.getAllKeys('小王')
req.onsuccess = () => {
console.log('get result', req.result) // [3, "1234", "5678"]
}
}
使用游标检索
查询索引数据
IDBIndex.openCursor(query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): IDBRequest<IDBCursorWithValue | null>
IDBCursorWithValue.value: any
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.openCursor('小王')
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
console.log('get', cursor.value, cursor.key, cursor.primaryKey)
}
}
// {name: "小王", phone: "13122228888", addr: "D", id: 3} 小王 3
}
- 查询所有索引数据
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.openCursor('小王')
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
console.log('get', cursor.value, cursor.key, cursor.primaryKey)
cursor.continue()
}
}
// {name: "小王", phone: "13122228888", addr: "D", id: 3} 小王 3
// {name: "小王", phone: "13122223333", addr: "A", id: "1234"} 小王 1234
// {name: "小王", phone: "13122224444", addr: "B", id: "5678"} 小王 5678
}
更新索引数据
IDBCursor.update(value: any): IDBRequest<IDBValidKey>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readwrite')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.openCursor('小王')
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
const data = cursor.value
// data.addr = `${data.addr}${Math.random() * 100 | 0}`
data.age = 25
const updataReq = cursor.update(data)
updataReq.onsuccess = () => {
console.log('update result', updataReq.result)
}
updataReq.onerror = () => { /*...*/ }
cursor.continue()
}
}
// 3 1234 5678
}
删除索引数据
IDBCursor.delete(): IDBRequest<undefined>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readwrite')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const index = store.index('name')
const req = index.openCursor('小王')
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
const data = cursor.value
if (data.addr.includes('A')) {
const delReq = cursor.delete()
delReq.onsuccess = () => {
console.log('del result', delReq.result)
}
delReq.onerror = (e) => { /*...*/ }
}
cursor.continue()
}
}
}
查询主键数据
IDBObjectStore.openCursor(query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): IDBRequest<IDBCursorWithValue | null>
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.openCursor()
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
console.log('get', cursor.value, cursor.key, cursor.primaryKey)
cursor.continue()
}
}
// {name: "小吴", phone: "13122227777", addr: "D", id: 2} 2 2
// {name: "小王", phone: "13122228888", addr: "D", id: 3, age: 25} 3 3
// {name: "小王", phone: "13122224444", addr: "B", id: "5678", age: 25} 5678 5678
}
遍历数据
- 设置步长
IDBCursor.advance(count: number): void
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.openCursor()
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
console.log('get', cursor.value)
cursor.advance(2)
}
}
// {name: "小吴", phone: "13122227777", addr: "D", id: 2}
// {name: "小王", phone: "13122224444", addr: "B", id: "5678", age: 25}
}
- 设置目标
IDBCursor.continue(key?: IDBValidKey): void
const openReq = indexedDB.open('test', 15)
openReq.onsuccess = () => {
const db = openReq.result
const tx = db.transaction('user_info', 'readonly')
tx.oncomplete = () => { /*...*/ }
const store = tx.objectStore('user_info')
const req = store.openCursor()
req.onsuccess = () => {
const cursor = req.result
if (cursor) {
console.log('get', cursor.value)
if (cursor.primaryKey !== '5678') {
cursor.continue('5678')
}
}
}
// {name: "小吴", phone: "13122227777", addr: "D", id: 2}
// {name: "小王", phone: "13122224444", addr: "B", id: "5678", age: 25}
}
补充
升级版本
- 方式:指定更高的版本号
- 时机1:需要创建、删除对象仓库
- 时机2:需要创建、删除索引
管理数据库版本号的类
不考虑兼容性,可以使用
indexedDB.databases().then(databases => console.log(databases))
- 类
/**
* @class 这是一个记录数据库版本号的类
*/
class DataBases {
private readonly open: Promise<IDBDatabase>
private constructor() {
this.open = this.openDB()
}
private openDB() {
return new Promise<IDBDatabase>((resolve, reject) => {
console.log('open db')
const openReq = indexedDB.open('databases')
openReq.onupgradeneeded = () => openReq.result.createObjectStore('databases')
openReq.onsuccess = () => resolve(openReq.result)
openReq.onerror = () => reject(openReq.error)
})
}
private useStore(callback: (store: IDBObjectStore) => void, mode: IDBTransactionMode = 'readonly') {
return this.open.then(db => {
return new Promise<void>((resolve, reject) => {
const tx = db.transaction('databases', mode)
tx.oncomplete = () => resolve()
tx.onabort = tx.onerror = (e) => reject(tx.error)
callback(tx.objectStore('databases'))
})
})
}
get(key) {
let version = 1
return this.useStore(store => {
store.get(key).onsuccess = (e) => {
version = (e.target as IDBRequest).result || 1
}
}).then(() => version)
}
set(key, value) {
return this.useStore(store => { store.put(value, key) }, 'readwrite').then(() => value)
}
del(key) {
return this.useStore(store => { store.delete(key) }, 'readwrite')
}
key(index: number) {
let name: string
return this.useStore(store => {
store.getAllKeys().onsuccess = (e) => {
const keys = (e.target as IDBRequest).result
name = index >= 0 && index <= keys.length - 1 ? keys[index] : null
}
}).then(() => name || null)
}
length() {
let len = 0
return this.useStore(store => {
store.count().onsuccess = (e) => {
len = (e.target as IDBRequest).result || 0
}
}).then(() => len)
}
private static _instance: DataBases
static getInstance(): DataBases {
if (!DataBases._instance) {
DataBases._instance = new DataBases()
}
return DataBases._instance
}
static getVersion(dbName: string) {
return DataBases.getInstance().get(dbName)
}
static setVersion(dbName: string, version: number) {
return DataBases.getInstance().set(dbName, version)
}
static removeVersion(dbName: string) {
return DataBases.getInstance().del(dbName)
}
static getKey(index: number) {
return DataBases.getInstance().key(index)
}
static getLength() {
return DataBases.getInstance().length()
}
}
- 使用
DataBases.getVersion('testdb').then(version => {
console.log('get version', version) // get version 1
return DataBases.setVersion('testdb', ++version)
}).then(newVersion => {
console.log('set version', newVersion) // set version 2
return DataBases.getLength()
}).then(len => {
console.log('get length', len) // get length 1
return DataBases.getKey(len - 1)
}).then(key => {
console.log('get key', key) // get key testdb
return DataBases.removeVersion('testdb')
}).then(() => {
console.log('remove success') // remove success
})