外國(guó)網(wǎng)站學(xué)習(xí)做任務(wù) 升級(jí)100大看免費(fèi)行情的軟件
連接數(shù)據(jù)庫(kù)
我們首先創(chuàng)建一個(gè)DBManager類(lèi),通過(guò)這個(gè)類(lèi)new出來(lái)的對(duì)象管理一個(gè)數(shù)據(jù)庫(kù)
具體關(guān)于indexedDB的相關(guān)內(nèi)容可以看我的這篇博客
indexedDB
class DBManager{}
我們首先需要打開(kāi)數(shù)據(jù)庫(kù),打開(kāi)數(shù)據(jù)庫(kù)需要數(shù)據(jù)庫(kù)名和該數(shù)據(jù)庫(kù)的版本
constructor(dbName, version) {this.dbName = dbName;this.version = version;this.db = null
}
在constructor中我們先初始化數(shù)據(jù)庫(kù)相關(guān)信息,dbName為該對(duì)象管理的數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)名,version為該數(shù)據(jù)庫(kù)的版本,db為該數(shù)據(jù)庫(kù)的IDBDatabase對(duì)象
現(xiàn)在我們開(kāi)始實(shí)現(xiàn)openDB方法
openDB() {return new Promise((resolve, reject) => {const cmd = indexedDB.open(this.dbName, this.version)cmd.onsuccess = (event) => {console.log('數(shù)據(jù)庫(kù)打開(kāi)成功')this.db = event.target.resultresolve(this.db)}cmd.onerror = (event) => {console.log('數(shù)據(jù)庫(kù)打開(kāi)失敗')reject(event.target.error)}})
}
因?yàn)榇蜷_(kāi)數(shù)據(jù)庫(kù)涉及i/o操作,所以是異步的,所以我們需要返回一個(gè)Promise
關(guān)閉數(shù)據(jù)庫(kù)
當(dāng)數(shù)據(jù)庫(kù)使用完畢,為了節(jié)省資源,我們可以選擇斷開(kāi)數(shù)據(jù)庫(kù)的連接
closeDB() {if (this.db) {console.log('關(guān)閉數(shù)據(jù)庫(kù)')this.db.close()this.db = null}
}
刪除數(shù)據(jù)庫(kù)
如果數(shù)據(jù)庫(kù)某一天不在使用,我們可以選擇刪除這個(gè)數(shù)據(jù)庫(kù)來(lái)節(jié)省資源
deleteDB() {return new Promise((resolve, reject) => {const cmd = indexedDB.deleteDatabase(this.dbName)cmd.onsuccess = (event) => {console.log('數(shù)據(jù)庫(kù)刪除成功')resolve()}cmd.onerror = (event) => {console.log('數(shù)據(jù)庫(kù)刪除失敗')reject(event.target.error)}})
}
同樣,刪除數(shù)據(jù)庫(kù)是異步的,我們需要返回一個(gè)Promise
我們接下來(lái)來(lái)測(cè)試一下
(async function () {const db = new DBManager("student", 1)await db.openDB()await db.closeDB()await db.deleteDB()
})()
需要注意的是,我們?cè)趧h除數(shù)據(jù)庫(kù)之前必須先斷開(kāi)數(shù)據(jù)庫(kù)連接
創(chuàng)建對(duì)象倉(cāng)庫(kù)
我們接下來(lái)需要實(shí)現(xiàn)創(chuàng)建對(duì)象的方法
createStore(storeName, keyPath, keys) {return new Promise((resolve, reject) => {if (this.db) {console.log('添加存儲(chǔ)倉(cāng)庫(kù)', storeName)const store = this.db.createObjectStore(storeName, { keyPath: keyPath, autoIncrement: true })if (keys) {keys.forEach(key => {store.createIndex(key, key, { unique: key === keyPath ? true : false })})}resolve(this.db)} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})
}
但是如果我們直接通過(guò)調(diào)用createStore來(lái)創(chuàng)建對(duì)象倉(cāng)庫(kù)的話(huà)瀏覽器會(huì)報(bào)錯(cuò)
這是因?yàn)獒槍?duì)對(duì)象倉(cāng)庫(kù)的操作是需要放在db.onupgradeneeded的回調(diào)中,所以我們不能直接這么寫(xiě)
數(shù)據(jù)庫(kù)的更新
我們可以用一個(gè)更新方法來(lái)手動(dòng)觸發(fā)onupgradeneeded這個(gè)事件
updateDB(callback) {return new Promise(async (resolve, reject) => {console.log('數(shù)據(jù)庫(kù)升級(jí)')if (this.db) {this.closeDB()this.version += 1await this.openDB(callback)resolve(this.db)}else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})
}
openDB(callback) {return new Promise((resolve, reject) => {const cmd = indexedDB.open(this.dbName, this.version)cmd.onsuccess = (event) => {console.log('數(shù)據(jù)庫(kù)打開(kāi)成功')this.db = event.target.resultresolve(this.db)}cmd.onerror = (event) => {console.log('數(shù)據(jù)庫(kù)打開(kāi)失敗')reject(event.target.error)}if (callback) {cmd.onupgradeneeded = (event) => {this.db = event.target.resultcallback(event)}}})
}
update方法通過(guò)調(diào)用close和open方法更新數(shù)據(jù)庫(kù),同時(shí)將對(duì)對(duì)象倉(cāng)庫(kù)的操作封裝成函數(shù)傳入update方法中,再將這個(gè)函數(shù)放入open方法中,open方法中通過(guò)判斷是否傳入?yún)?shù)來(lái)判斷是否需要監(jiān)聽(tīng)onupgradeneeded事件,因?yàn)楫?dāng)用戶(hù)第一次創(chuàng)建數(shù)據(jù)庫(kù)的時(shí)候會(huì)觸發(fā)這個(gè)事件,而第一次的時(shí)候我們是不需要監(jiān)聽(tīng)的
接下來(lái)我們重新處理下createStore里的邏輯
createStore(storeName, keyPath, keys) {return new Promise(async (resolve, reject) => {if (this.db) {await this.updateDB((event) => {console.log('添加存儲(chǔ)倉(cāng)庫(kù)', storeName)const store = this.db.createObjectStore(storeName, { keyPath: keyPath, autoIncrement: true })if (keys) {keys.forEach(key => {store.createIndex(key, key, { unique: key === keyPath ? true : false })})}})resolve(this.db)} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})
}
接下來(lái)我們?cè)賮?lái)測(cè)試一下
(async function () {const db = new DBManager("student", 1)await db.openDB()await db.createStore("student", "id", ['id', 'name', 'age', 'score'])await db.closeDB()await db.deleteDB()
})()
為什么是先打印添加存儲(chǔ)倉(cāng)庫(kù),后打印數(shù)據(jù)庫(kù)打開(kāi)?因?yàn)楫?dāng)IDBDatabase對(duì)象同時(shí)出發(fā)onsuccess和onupgradeneeded事件時(shí),會(huì)先執(zhí)行onupgradeneeded的回調(diào),然后執(zhí)行onsuccess中的回調(diào)
數(shù)據(jù)記錄的操作
我們接下來(lái)實(shí)現(xiàn)關(guān)于數(shù)據(jù)記錄的方法
增加數(shù)據(jù)
增加數(shù)據(jù)記錄的邏輯較為簡(jiǎn)單,調(diào)用indexedDB提供的add方法就行
insert(storeName, data) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readwrite')const store = transaction.objectStore(storeName)const cmd = store.add(data)cmd.onsuccess = (event) => {console.log('插入數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('插入數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})
}
我們來(lái)測(cè)試一下
(async function () {const db = new DBManager("student", 1)await db.openDB()await db.createStore("student", "id", ['id', 'name', 'age', 'score'])await db.insert("student", { id: 1, name: "張三", age: 18, score: 90 })await db.insert("student", { id: 2, name: "李四", age: 20, score: 56 })await db.closeDB()await db.deleteDB()
})()
查詢(xún)數(shù)據(jù)
查詢(xún)數(shù)據(jù)我們需要根據(jù)不同的查詢(xún)方式來(lái)實(shí)現(xiàn)不同的方法
-
通過(guò)key查詢(xún)
queryByKey(storeName, value) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cmd = store.get(value)cmd.onsuccess = (event) => {console.log('查詢(xún)數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}}) }
-
查詢(xún)?nèi)繑?shù)據(jù)記錄
queryAll(storeName) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cmd = store.getAll()cmd.onsuccess = (event) => {console.log('查詢(xún)數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}}) }
-
通過(guò)游標(biāo)查詢(xún)
queryByCursor(storeName, range, direction = "next") {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cursor = range ? store.openCursor(range, direction) : store.openCursor()const result = []cursor.onsuccess = (event) => {const cursor = event.target.resultif (cursor) {result.push(cursor.value)cursor.continue()} else {console.log('查詢(xún)數(shù)據(jù)成功')resolve(result)}}cursor.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}}) }
-
通過(guò)指定key-value查詢(xún)
queryByIndex(storeName, indexName, value) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cmd = store.index(indexName).get(value)cmd.onsuccess = (event) => {console.log('查詢(xún)數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}}) }
我們現(xiàn)在來(lái)測(cè)試一下
(async function () {const db = new DBManager("student", 1)await db.openDB()await db.createStore("student", "id", ['id', 'name', 'age', 'score'])await db.insert("student", { id: 1, name: "張三", age: 18, score: 90 })await db.insert("student", { id: 2, name: "李四", age: 20, score: 56 })await db.insert("student", { id: 3, name: "王五", age: 19, score: 80 })await db.insert("student", { id: 4, name: "趙六", score: 70 })const result = await db.queryByIndex("student", "age", 18)console.log(result)const result2 = await db.queryByKey("student", 3)console.log(result2)const result3 = await db.queryByCursor("student")console.log(result3)const result4 = await db.queryByCursor("student", IDBKeyRange.only(4))console.log(result4)const result5 = await db.queryAll("student")console.log(result5)await db.closeDB()await db.deleteDB()
})()
更新數(shù)據(jù)
更新數(shù)據(jù)記錄也是通過(guò)調(diào)用indexedDB中的put方法來(lái)實(shí)現(xiàn)
update(storeName, key, data) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readwrite')const store = transaction.objectStore(storeName)const cmd = store.put(data)cmd.onsuccess = (event) => {console.log('更新數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('更新數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})
}
刪除數(shù)據(jù)
更新數(shù)據(jù)記錄也是通過(guò)調(diào)用indexedDB中的delete方法來(lái)實(shí)現(xiàn)
delete(storeName, key) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readwrite')const store = transaction.objectStore(storeName)const cmd = store.delete(key)cmd.onsuccess = (event) => {console.log('刪除數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('刪除數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})
}
完整代碼
最后我們來(lái)看一下完整代碼
class DBManager {constructor(dbName, version) {this.dbName = dbName;this.version = version;this.db = null}openDB(callback) {return new Promise((resolve, reject) => {const cmd = indexedDB.open(this.dbName, this.version)cmd.onsuccess = (event) => {console.log('數(shù)據(jù)庫(kù)打開(kāi)成功')this.db = event.target.resultresolve(this.db)}cmd.onerror = (event) => {console.log('數(shù)據(jù)庫(kù)打開(kāi)失敗')reject(event.target.error)}if (callback) {cmd.onupgradeneeded = (event) => {this.db = event.target.resultcallback(event)}}})}closeDB() {if (this.db) {console.log('關(guān)閉數(shù)據(jù)庫(kù)')this.db.close()this.db = null}}deleteDB() {return new Promise((resolve, reject) => {const cmd = indexedDB.deleteDatabase(this.dbName)cmd.onsuccess = (event) => {console.log('數(shù)據(jù)庫(kù)刪除成功')resolve()}cmd.onerror = (event) => {console.log('數(shù)據(jù)庫(kù)刪除失敗')reject(event.target.error)}})}updateDB(callback) {return new Promise(async (resolve, reject) => {console.log('數(shù)據(jù)庫(kù)升級(jí)')if (this.db) {this.closeDB()this.version += 1await this.openDB(callback)resolve(this.db)}else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}createStore(storeName, keyPath, keys) {return new Promise(async (resolve, reject) => {if (this.db) {await this.updateDB((event) => {console.log('添加存儲(chǔ)倉(cāng)庫(kù)', storeName)const store = this.db.createObjectStore(storeName, { keyPath: keyPath, autoIncrement: true })if (keys) {keys.forEach(key => {store.createIndex(key, key, { unique: key === keyPath ? true : false })})}})resolve(this.db)} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}deleteStore(storeName) {return new Promise(async (resolve, reject) => {if (this.db) {await this.updateDB((event) => {console.log('刪除存儲(chǔ)倉(cāng)庫(kù)', storeName)const store = this.db.deleteObjectStore(storeName)})resolve(this.db)} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}insert(storeName, data) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readwrite')const store = transaction.objectStore(storeName)const cmd = store.add(data)cmd.onsuccess = (event) => {console.log('插入數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('插入數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}update(storeName, key, data) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readwrite')const store = transaction.objectStore(storeName)const cmd = store.put(data)cmd.onsuccess = (event) => {console.log('更新數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('更新數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}delete(storeName, key) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readwrite')const store = transaction.objectStore(storeName)const cmd = store.delete(key)cmd.onsuccess = (event) => {console.log('刪除數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('刪除數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}queryByKey(storeName, value) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cmd = store.get(value)cmd.onsuccess = (event) => {console.log('查詢(xún)數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}queryAll(storeName) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cmd = store.getAll()cmd.onsuccess = (event) => {console.log('查詢(xún)數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}queryByIndex(storeName, indexName, value) {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cmd = store.index(indexName).get(value)cmd.onsuccess = (event) => {console.log('查詢(xún)數(shù)據(jù)成功')resolve(event.target.result)}cmd.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}queryByCursor(storeName, range, direction = "next") {return new Promise((resolve, reject) => {if (this.db) {const transaction = this.db.transaction(storeName, 'readonly')const store = transaction.objectStore(storeName)const cursor = range ? store.openCursor(range, direction) : store.openCursor()const result = []cursor.onsuccess = (event) => {const cursor = event.target.resultif (cursor) {result.push(cursor.value)cursor.continue()} else {console.log('查詢(xún)數(shù)據(jù)成功')resolve(result)}}cursor.onerror = (event) => {console.log('查詢(xún)數(shù)據(jù)失敗')reject(event.target.error)}} else {reject('數(shù)據(jù)庫(kù)未打開(kāi)')}})}
}