第二个参数是数据库的版本。版本决定了数据库的模式:存储在里面的 object store 和它们的结构。当第一次通过 open 方法打开数据库时,会触发一个 onupgradeneeded 事件,我们可以也只能在这里设置数据库模式。当数据库已经存在,而我们打开一个更高版本时,同样会触发 onupgradeneeded 事件,用来更新数据库模式。
前面已经说过,当创建或者增大数据库版本的时候,会触发 onupgradeneeded 事件。在事件内部,可以拿到 db 对象来创建或更新 object store , 具体如下。
request.onupgradeneeded = function (event) { /** * NOTE: * 1. 创建新的 objectStore * 2. 删除旧的不需要的 objectStore * 3. 如果需要更新已有 objectStore 的结构,需要先删除原有的 objectStore ,然后重新创建 */ // The IDBDatabase interface console.log('onupgradeneeded', event) var db = event.target.result // Create an objectStore for this database const objectStore = db.createObjectStore(OB_NAMES.UseKeyPath, { keyPath: 'time' }) }
3. 构建数据库
indexedDB 是以对象存储(object store)而不是以表结构存储的,一个数据库可以存储任意多个存储对象。每当有一个值存储在 object store 里面,就必须和一个 key 关联起来。有几种提供 key 的方法,取决于 object store 使用 key path 还是 key generator.
它们之间区别,借用 MDN 的一个表格来看一下:
Key Path (keyPath)
Key Generator (autoIncrement)
Description
No
No
This object store can hold any kind of value, even primitive values like numbers and strings. You must supply a separate key argument whenever you want to add a new value.
Yes
No
This object store can only hold JavaScript objects. The objects must have a property with the same name as the key path.
No
Yes
This object store can hold any kind of value. The key is generated for you automatically, or you can supply a separate key argument if you want to use a specific key.
Yes
Yes
This object store can only hold JavaScript objects. Usually a key is generated and the value of the generated key is stored in the object in a property with the same name as the key path. However, if such a property already exists, the value of that property is used as key rather than generating a new key.
functionopenindexedDB () { // The call to the open() function returns an IDBOpenDBRequest object with a result (success) or error value that you handle as an event. returnnewPromise((resolve, reject) => { /** * NOTE: * 1. 第一次打开可能会提示用户获取 indexedDB 的权限 * 2. 浏览器隐身模式不会存在本地,只会存储在内存中 */ const request = window.indexedDB.open(DB_NAME, DB_VERSION) request.onerror = function (event) { // Do something with request.errorCode! console.log('open request failed', event) console.error(event.target.error) } request.onsuccess = function (event) { // Do something with request.result! // console.log('open request success', event) var db = event.target.result db.onerror = function (e) { console.error('Database error: ', e.target.error) reject(e.target.error) } db.onclose = e => { console.error('Database close:', e.target.error) reject(e.target.error) } resolve(db) } request.onupgradeneeded = function (event) { /** * NOTE: * 1. 创建新的 objectStore * 2. 删除旧的不需要的 objectStore * 3. 如果需要更新已有 objectStore 的结构,需要先删除原有的 objectStore ,然后重新创建 */ // The IDBDatabase interface console.log('onupgradeneeded', event) var db = event.target.result // Create an objectStore for this database obUseKeypath(db) obUseKeyGenerator(db) /** * NOTE: * transaction * 三个事件: * 1. error * 2. abort * 3. complete * 两个方法: * 1. abort * Rolls back all the changes to objects in the database associated with this transaction. If this transaction has been aborted or completed, then this method throws an error event. * 2. objectStore * Returns an IDBObjectStore object representing an object store that is part of the scope of this transaction. */ db.transaction.oncomplete = function (e) { console.log('obj create success', e) } } }) } functionobUseKeypath (db) { const objectStore = db.createObjectStore(OB_NAMES.UseKeyPath, { keyPath: 'time' }) objectStore.createIndex('errorCode', 'errorCode', { unique: false }) objectStore.createIndex('level', 'level', { unique: false }) } functionobUseKeyGenerator (db) { const objectStore = db.createObjectStore(OB_NAMES.UseKeyGenerator, { autoIncrement: true }) objectStore.createIndex('errorCode', 'errorCode', { unique: false }) objectStore.createIndex('time', 'time', { unique: true }) objectStore.createIndex('level', 'level', { unique: false }) }