• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

使用indexedDB的正确打开方式和多种使用场景

武飞扬头像
0522Skylar
帮助9

针对以下场景,在不使用库的情况下,如何使用indexedDB数据库, 下面将介绍使用直接使用indexedDB的痛点, 最后给出解决方案

痛点1: 一个页面一个数据库,一张数据表

一张数据表,大家应该都能够操作,但你会发现,只是简简单单的使用api,会出现一些意外情况,怎么解决这样的意外情况呢?请看下面的小demo


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

  </head>
  <body>
		<div>id: <input id="id" /></div>
    <br />

    <div>str: <input id="str" /></div>
    <br />
    <button id="add">新增数据</button>
    <button id="search">查询数据</button>
    <button id="delete">删除数据</button>
    <button id="remove">删除表</button>


    <script>
    const dataSheetName = "tableTest"
    const dataBaseName = "dataABC"
    let request = window.indexedDB.open(dataBaseName)
    let dataBase = null;

    let version = null;
    request.onerror = (event) => {
      console.error('dataBase打开报错', event.target.error)
    }
    request.onsuccess = (event) => {
      dataBase = event.target.result
      version = event.target.result.version
      console.info('dataBase打开成功', event.target.result)
    }
    // 新建数据表
    request.onupgradeneeded = (event) => {
      dataBase = event.target.result
      let objectStore = null
      console.info('dataBase建表')
      objectStore = dataBase.createObjectStore(dataSheetName, {
        keyPath: "id"
      })
      // 新建索引
      objectStore.createIndex("str", "str", {unique: false})
    }

    document.querySelector("#add").onclick = () => {
      const id = document.querySelector("#id").value
      const str = document.querySelector("#str").value
        request = dataBase.transaction(dataSheetName, 'readwrite')
        .objectStore(dataSheetName)
        .put({id, str})

        request.onsuccess = () => {
          console.info('write data success')
        }
        request.onerror = (e) => {
          console.error('write data fail')
        }
    }


    document.querySelector("#search").onclick = () => {
      const key = document.querySelector("#id").value
      const objectStore = dataBase.transaction([dataSheetName]).objectStore(dataSheetName)
      const request = objectStore.get(key)
      request.onerror = (e) => {
        console.error('read dataBase fail')
      }
      request.onsuccess = () => {
        if (request.result) {
          console.log('search successful!!!!', request.result)
        } else {
          console.info('not find any data')
        }
      }
    }


    document.querySelector("#delete").onclick = () => {
      const key = document.querySelector("#id").value
      request = dataBase.transaction([dataSheetName], 'readwrite')
      .objectStore(dataSheetName)
      .delete(key)
      request.onsuccess = (e) => {
        console.info('dataBase数据删除成功', e)
      }
      request.onerror = (e) => {
        console.error('dataBase数据删除事务失败')
      }
    }


    document.querySelector("#remove").onclick = () => {
      dataBase.close();
      version  
      console.log(version)

    request = window.indexedDB.open(dataBaseName, version);


      request.onerror = (event) => {
        console.error(event.target.error)
      };
      request.onsuccess = (event) => {
        dataBase.close();
        version = event.target.result.version
        console.log('delet success')
      }
      request.onupgradeneeded = (event) => {
        dataBase = event.target.result;
        version = dataBase.version;
        dataBase.deleteObjectStore(dataSheetName);
        console.log(event.target, 'delete success')
      };
    }

  </script>
  </body>
</html>
学新通

但是当你删除这张表, 刷新这个页面, 再次打开时,你就会发现不能正常进行操作了

学新通

Uncaught DOMException: Failed to execute ‘transaction’ on ‘IDBDatabase’: One of the specified object stores was not found.

why?
这是简单的操作,而且也经常用到,原因就是version
每次open一个数据库,如果需要操作数据表,就必须要在onupgradeneeded回调里面执行,但是只有version发生变化,才会再次调用onupgradeneeded

上面的原因就是删除表之后,改变了原来的version

下次再次打开, 就必须要重新建表,而建表的操作是需要onupgradeneeded,而onupgradeneeded回调执行,需要version再次发生变化

也就是初次建表,version为1,删除表, version为2
当再次建立表. 需要version为3,才会执行onupgradeneeded回调,重新见表
但是这个version一个变量不可以保存到在页面上,页面上的变量会随着页面刷新而被垃圾回收,
如何保存这个version下次还能再次使用且不影响下次页面重新建表

如何解决下面会讲到,先讲完所有案例会出现的意外情况先

痛点2:一个页面一个数据库,两张数据表

当存在同一个数据库,两个表时, 同时要初始化两个表
当删除表之后,下次再次打开,进行数据库增删改查操作,出错, 版本不对

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="tableA">
    <p>tableA</p>
    <div>id: <input class="id" /></div>
    <br />

    <div>str: <input class="str" /></div>
    <br />
    <button class="add">新增数据</button>
    <button class="search">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="remove">删除表</button>
  </div>
  <div id="tableB">
    <p>tableB</p>
    <div>id: <input class="id" /></div>
    <br />

    <div>str: <input class="str" /></div>
    <br />
    <button class="add">新增数据</button>
    <button class="search">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="remove">删除表</button>
  </div>
  <script>
    let dataBase = null;

    let version = null;
    
    function openBase(dataBaseName, dataSheetName1, dataSheetName2) {
      if(dataBase != null) {
        dataBase.close()
      }
      let request = window.indexedDB.open(dataBaseName)
      request.onerror = (event) => {
        console.error('dataBase打开报错', event.target.error)
      }
      request.onsuccess = (event) => {
        dataBase = event.target.result
        version = event.target.result.version
        console.info('dataBase打开成功', event.target.result, version)
      }
      // 新建数据表
      request.onupgradeneeded = (event) => {
        dataBase = event.target.result
        // let objectStore = null
        console.info('dataBase建表')
        let objectStore1 = dataBase.createObjectStore(dataSheetName1, {
          keyPath: "id"
        })
        // 新建索引
        objectStore1.createIndex("str", "str", {unique: false})

        let objectStore2 = dataBase.createObjectStore(dataSheetName2, {
          keyPath: "id"
        })
        // 新建索引
        objectStore2.createIndex("str", "str", {unique: false})
      }
    }

    openBase("baseA", "tableA", "tableB")
    document.querySelector("#tableA .add").onclick = () => {
      const id = document.querySelector("#tableA .id").value
      const str = document.querySelector("#tableA .str").value
        request = dataBase.transaction("tableA", 'readwrite')
        .objectStore("tableA")
        .put({id, str})

        request.onsuccess = () => {
          console.info('tableA write data success')
        }
        request.onerror = (e) => {
          console.error('tableA write data fail')
        }
    }
    document.querySelector("#tableB .add").onclick = () => {
      const id = document.querySelector("#tableB .id").value
      const str = document.querySelector("#tableB .str").value
        request = dataBase.transaction("tableB", 'readwrite')
        .objectStore("tableB")
        .put({id, str})

        request.onsuccess = () => {
          console.info('tableB write data success')
        }
        request.onerror = (e) => {
          console.error('tableB write data fail')
        }
    }


    document.querySelector("#tableA .search").onclick = () => {
      const key = document.querySelector("#tableA .id").value
      const objectStore = dataBase.transaction(['tableA']).objectStore('tableA')
      const request = objectStore.get(key)
      request.onerror = (e) => {
        console.error('#tableA . read dataBase fail')
      }
      request.onsuccess = () => {
        if (request.result) {
          console.log('#tableA . search successful!!!!', request.result)
        } else {
          console.info('tableA not find any data')
        }
      }
    }


    document.querySelector("#tableB .search").onclick = () => {
      const key = document.querySelector("#tableB .id").value
      const objectStore = dataBase.transaction(['tableB']).objectStore('tableB')
      const request = objectStore.get(key)
      request.onerror = (e) => {
        console.error('#tableB . read dataBase fail')
      }
      request.onsuccess = () => {
        if (request.result) {
          console.log('#tableB . search successful!!!!', request.result)
        } else {
          console.info('tableB not find any data')
        }
      }
    }


    document.querySelector("#tableA .delete").onclick = () => {
      const key = document.querySelector("#tableA .id").value
      request = dataBase.transaction(['tableA'], 'readwrite')
      .objectStore('tableA')
      .delete(key)
      request.onsuccess = (e) => {
        console.info('tableA dataBase数据删除成功', e)
      }
      request.onerror = (e) => {
        console.error('tableA dataBase数据删除事务失败')
      }
    }

    document.querySelector("#tableB .delete").onclick = () => {

      const key = document.querySelector("#tableB .id").value
      request = dataBase.transaction(['tableB'], 'readwrite')
      .objectStore('tableB')
      .delete(key)
      request.onsuccess = (e) => {
        console.info('tableB dataBase数据删除成功', e)
      }
      request.onerror = (e) => {
        console.error('tableB dataBase数据删除事务失败')
      }
    }

    document.querySelector("#tableA .remove").onclick = () => {
      dataBase.close();
      version  
      console.log(version)
      request = window.indexedDB.open('baseA', version);
      request.onerror = (event) => {
        console.error(event.target.error)
      };
      request.onsuccess = (event) => {
        // dataBase.close();
        version = event.target.result.version
        console.log('delet success')
      }
      request.onupgradeneeded = (event) => {
        dataBase = event.target.result;
        version = dataBase.version;
        dataBase.deleteObjectStore('tableA');
        console.log(event.target, 'tableA delete success')
      };
    }
    document.querySelector("#tableB .remove").onclick = () => {
      dataBase.close();
      version  
      console.log(version)
      request = window.indexedDB.open('baseA', version);
      request.onerror = (event) => {
        console.error(event.target.error)
      };
      request.onsuccess = (event) => {
        // dataBase.close();
        version = event.target.result.version
        console.log('delet success')
      }
      request.onupgradeneeded = (event) => {
        dataBase = event.target.result;
        version = dataBase.version;
        dataBase.deleteObjectStore('tableB');
        console.log(event.target, ' tableB delete success')
      };
    }
  </script>
</body>

</html>

学新通

学新通

报错依然很眼熟,没有重新建表,就去使用这个表了, indexedDB中,表就是store
Uncaught DOMException: Failed to execute ‘transaction’ on ‘IDBDatabase’: One of the specified object stores was not found.

这个跟上面的错误原因是一样的
并且删除表的时候,也是报错version的原因
DOMException: Version change transaction was aborted in upgradeneeded event handler.

痛点3:一个页面多个数据库,多张表

当存在不同数据库, 不同表, 初始化不可以共用, 且数据库不同, 所以争对不同的数据库操作也是根据数据库来的
当删除表之后,下次再次打开,进行数据库增删改查操作,出错, 版本不对

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="tableA">
    <p>baseA, tableA</p>
    <div>id: <input class="id" /></div>
    <br />

    <div>str: <input class="str" /></div>
    <br />
    <button class="add">新增数据</button>
    <button class="search">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="remove">删除表</button>
  </div>
  <div id="tableB">
    <p>baseB, tableB</p>
    <div>id: <input class="id" /></div>
    <br />

    <div>str: <input class="str" /></div>
    <br />
    <button class="add">新增数据</button>
    <button class="search">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="remove">删除表</button>
  </div>
  <script>
    

    let version = null;
    let dataBaseA = null;
    let dataBaseB = null;
    
    function openBase1() {
      let request = window.indexedDB.open("baseA")
      request.onerror = (event) => {
        console.error('dataBase打开报错', event.target.error)
      }
      request.onsuccess = (event) => {
        dataBaseA = event.target.result
        version = event.target.result.version
        console.log('dataBaseA open success')

      }
      // 新建数据表
      request.onupgradeneeded = (event) => {
        dataBaseA = event.target.result
        // let objectStore = null
        console.info('datadataBaseA建表')
        let objectStore1 = dataBaseA.createObjectStore("tableA", {
          keyPath: "id"
        })
        // 新建索引
        objectStore1.createIndex("str", "str", {unique: false})
      }
    }

    function openBase2() {
      let request = window.indexedDB.open("baseB")
      request.onerror = (event) => {
        console.error('dataBase打开报错', event.target.error)
      }
      request.onsuccess = (event) => {
        dataBaseB = event.target.result
        version = event.target.result.version
        console.log('dataBaseB open success')
      }
      // 新建数据表
      request.onupgradeneeded = (event) => {
        dataBaseB = event.target.result
        // let objectStore = null
        console.info('dataBaseb建表')
        let objectStore1 = dataBaseB.createObjectStore("tableB", {
          keyPath: "id"
        })
        // 新建索引
        objectStore1.createIndex("str", "str", {unique: false})
      }
    }
    openBase1()
    openBase2()
    document.querySelector("#tableA .add").onclick = () => {
      const id = document.querySelector("#tableA .id").value
      const str = document.querySelector("#tableA .str").value
        request = dataBaseA.transaction("tableA", 'readwrite')
        .objectStore("tableA")
        .put({id, str})

        request.onsuccess = () => {
          console.info('tableA write data success')
        }
        request.onerror = (e) => {
          console.error('tableA write data fail')
        }
    }
    document.querySelector("#tableB .add").onclick = () => {
      const id = document.querySelector("#tableB .id").value
      const str = document.querySelector("#tableB .str").value
      console.log(dataBaseB, 11111)
        request = dataBaseB.transaction("tableB", 'readwrite')
        .objectStore("tableB")
        .put({id, str})

        request.onsuccess = () => {
          console.info('tableB write data success')
        }
        request.onerror = (e) => {
          console.error('tableB write data fail')
        }
    }


    document.querySelector("#tableA .search").onclick = () => {
      const key = document.querySelector("#tableA .id").value
      const objectStore = dataBaseA.transaction(['tableA']).objectStore('tableA')
      const request = objectStore.get(key)
      request.onerror = (e) => {
        console.error('#tableA . read dataBase fail')
      }
      request.onsuccess = () => {
        if (request.result) {
          console.log('#tableA . search successful!!!!', request.result)
        } else {
          console.info('tableA not find any data')
        }
      }
    }


    document.querySelector("#tableB .search").onclick = () => {
      const key = document.querySelector("#tableB .id").value
      const objectStore = dataBaseB.transaction(['tableB']).objectStore('tableB')
      const request = objectStore.get(key)
      request.onerror = (e) => {
        console.error('#tableB . read dataBase fail')
      }
      request.onsuccess = () => {
        if (request.result) {
          console.log('#tableB . search successful!!!!', request.result)
        } else {
          console.info('tableB not find any data')
        }
      }
    }


    document.querySelector("#tableA .delete").onclick = () => {
      const key = document.querySelector("#tableA .id").value
      request = dataBaseA.transaction(['tableA'], 'readwrite')
      .objectStore('tableA')
      .delete(key)
      request.onsuccess = (e) => {
        console.info('tableA dataBase数据删除成功', e)
      }
      request.onerror = (e) => {
        console.error('tableA dataBase数据删除事务失败')
      }
    }

    document.querySelector("#tableB .delete").onclick = () => {

      const key = document.querySelector("#tableB .id").value
      request = dataBaseB.transaction(['tableB'], 'readwrite')
      .objectStore('tableB')
      .delete(key)
      request.onsuccess = (e) => {
        console.info('tableB dataBase数据删除成功', e)
      }
      request.onerror = (e) => {
        console.error('tableB dataBase数据删除事务失败')
      }
    }

    document.querySelector("#tableA .remove").onclick = () => {
      dataBaseA.close();
      version  
      console.log(version)
      request = window.indexedDB.open('baseA', version);
      request.onerror = (event) => {
        console.error(event.target.error)
      };
      request.onsuccess = (event) => {
        version = event.target.result.version
        console.log('delet success')
      }
      request.onupgradeneeded = (event) => {
        dataBaseA = event.target.result;
        version = dataBaseA.version;
        dataBaseA.deleteObjectStore('tableA');
        console.log(event.target, 'tableA delete success')
      };
    }
    document.querySelector("#tableB .remove").onclick = () => {
      dataBaseB.close();
      version  
      console.log(version)
      request = window.indexedDB.open('baseB', version);
      request.onerror = (event) => {
        console.error(event.target.error)
      };
      request.onsuccess = (event) => {
        version = event.target.result.version
        console.log('delet success')
      }
      request.onupgradeneeded = (event) => {
        dataBaseB = event.target.result;
        version = dataBaseB.version;
        dataBaseB.deleteObjectStore('tableB');
        console.log(event.target, ' tableB delete success')
      };
    }
  </script>
</body>

</html>
学新通

学新通

看到这里, 大家会不会觉得每次删除数据库之后, 操作就会出现问题,那不删除数据表, 是不是就没有问题了?

学新通

确实没有删除表, 数据就能下次继续这样操作, 那是不是就可以这样封装了呢?

等等, 还有一种情况

痛点4:初始化页面就立刻进行数据表操作

这是什么操作呢?
就是页面一初始化完成, 就立刻往数据表里面新增内容, 或者立刻查询数据表, 这个时候会出现什么情况呢?
请看下面例子:


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

  </head>
  <body>
		<div>id: <input id="id" /></div>
    <br />

    <div>str: <input id="str" /></div>
    <br />
    <button id="add">新增数据</button>
    <button id="search">查询数据</button>
    <button id="delete">删除数据</button>
    <button id="remove">删除表</button>


    <script>
    const dataSheetName = "tableTest"
    const dataBaseName = "dataABC"
    let request = window.indexedDB.open(dataBaseName)
    let dataBase = null;

    let version = null;
    request.onerror = (event) => {
      console.error('dataBase打开报错', event.target.error)
    }
    request.onsuccess = (event) => {
      dataBase = event.target.result
      version = event.target.result.version
      console.info('dataBase打开成功', event.target.result)
    }
    // 新建数据表
    request.onupgradeneeded = (event) => {
      dataBase = event.target.result
      let objectStore = null
      console.info('dataBase建表')
      objectStore = dataBase.createObjectStore(dataSheetName, {
        keyPath: "id"
      })
      // 新建索引
      objectStore.createIndex("str", "str", {unique: false})
    }
    const initAdd = () => {
      // const id = document.querySelector("#id").value
      const id = "123"
      const str = "1234"
      // const str = document.querySelector("#str").value
        request = dataBase.transaction(dataSheetName, 'readwrite')
        .objectStore(dataSheetName)
        .put({id, str})
        console.log('add')
        request.onsuccess = () => {
          console.info('write data success')
        }
        request.onerror = (e) => {
          console.error('write data fail')
        }
    }
    initAdd();



  </script>
  </body>
</html>
学新通

学新通

Uncaught TypeError: Cannot read properties of null (reading ‘transaction’)

报错说dataBase为null
学新通

我们查看一下MDN文档里面是怎么说的
https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API
学新通

简单的情况,看起来很复杂, 其实就是说想要直接使用, 步骤比较多, 遇到的问题也很多
我们继续看, 如何使用indexedDB
https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB

IndexedDB 鼓励使用的基本模式如下所示:

  1. 打开数据库。
  2. 在数据库中创建一个对象仓库(object store)。
  3. 启动一个事务,并发送一个请求来执行一些数据库操作,像增加或提取数据等。
  4. 通过监听正确类型的 DOM 事件以等待操作完成。
  5. 在操作结果上进行一些操作(可以在 request 对象中找到)

这些基本模式, 我们通过上面的例子, 也已经非常清楚和了解了

这才是核心, 所有操作都是异步的, 这也很好解释了, 上面的报错, 就是因为dataBase还未初始化完毕, 所以导致的错误
学新通

只有当open的success回调执行完,dataBase才算真正初始化完成

解决: 封装一个简单的工具类

实现增删改查,实现上面这多种操作,复杂操作,例如阻塞未实现

首先我们考虑一下能否使用类来实现?一个数据表对应一个对象
异步回调,需要使用到promise,使用时可以用then继续回调,或者用async和await关键字
接下来,我们考虑初始化一张表需要执行的操作
然后就可以开始封装

我们初始化一张表格,需要哪些参数:
数据库名称(baseName)
数据表名称(sheetName)
主键(keyName)
索引(indexArr 数组)
version(版本)

直接看完整封装

export default class IndexedDB {
  dataBase = null; // 数据库
  dataBaseName = null; // 数据库名
  dataSheetName = null; // 数据表名
  keyName = '' // 主键
  indexArr = [] // 索引
  version = null
  constructor({
    baseName,
    sheetName,
    keyName,
    indexArr,
    version
  }) {
    // baseName: 数据库名称
    // sheetName:数据表名称
    // keyName:主键
    // indexArr: Array<name, unique> 索引<索引名, 索引是否重复(为true则表示同一个项的值不能重复)>
    this.dataBaseName = baseName
    this.dataSheetName = sheetName
    this.keyName = keyName
    this.indexArr = indexArr
    this.version = version
  }

  isReady(version) {
    return new Promise((resolve, reject) => {
      // 打开数据库
      const request = window.indexedDB.open(this.dataBaseName, version || this.version)
      request.onerror = (event) => {
        console.error('dataBase打开报错', event.target.error)
        reject(event.target.error)
      }
      request.onsuccess = (event) => {
        this.dataBase = event.target.result
        this.version = event.target.result.version
        console.info('dataBase打开成功', event.target.result)
        resolve()
      }
      // 新建数据表
      request.onupgradeneeded = (event) => {
        this.dataBase = event.target.result
        let objectStore = null
        if (!this.dataBase.objectStoreNames.contains(this.dataSheetName)) { // 不存在该数据表
          console.info('dataBase建表')
          objectStore = this.dataBase.createObjectStore(this.dataSheetName, {
            keyPath: this.keyName
          })
          // 新建索引
          this.indexArr.forEach(item => {
            objectStore.createIndex(item.name, item.name, {
              unique: item.unique || false
            })
          })
        }
      }
    })

  }
  // 写数据操作
  write(obj) {
    return new Promise((resolve, reject) => {
      // put()有则更新,无则新增
      const request = this.dataBase.transaction(this.dataSheetName, 'readwrite')
        .objectStore(this.dataSheetName)
        .put(obj)
      request.onsuccess = () => {
        console.info('write data success')
        resolve(this)
      }
      request.onerror = (e) => {
        console.error('write data fail')
        reject(e.target.error)
      }
    })
  }
  // 新增数据
  add(obj) {
    return new Promise((resolve, reject) => {
      if (this.dataBase.objectStoreNames.contains(this.dataSheetName)) { // 确定有表
        this.write(obj).then(() => {
          resolve()
        }).catch(err => {
          console.error(err);
          reject(err)
        })
      } else { // 如果表未成功建立
        // 第一步断开库连接
        this.dataBase.close()
        // 新增版本(必须新增版本,否则不会执行onupgradeneeded, 而表操作必须在onupgradeneeded回调中执行)
        this.version  ;
        // 第二步// 重新建表
        this.isReady().then(() => {
          // 重新写入数据
          this.write(obj).then(() => {
            resolve()
          })
        }).catch(err => {
          console.error(err);
          reject(err)
        })
      }
    })

  }
  // 更新数据
  update(obj) {
    // 没有该索引就新增,有就更新
    return new Promise((resolve, reject) => {
      this.add(obj).then(() => {
        resolve()
      }).catch((e) => {
        reject(e)
      })
    })

  }
  // 读取数据
  read(key) {
    // throw new Error('xxxxxxxxx')
    return new Promise((resolve, reject) => {
      // throw new Error('1111111')
      if (!this.dataBase.objectStoreNames.contains(this.dataSheetName)) {
        return resolve('未建表')
      }
      const objectStore = this.dataBase.transaction([this.dataSheetName]).objectStore(this.dataSheetName)
      const request = objectStore.get(key)
      request.onerror = (e) => {
        console.error('read dataBase fail')
        reject(e.target.error)
      }
      request.onsuccess = () => {
        if (request.result) {
          resolve(request.result)
        } else {
          console.info('not find any data')
          resolve(null)
        }
      }
    })
  }
  // 删除数据
  remove(key) {
    return new Promise((resolve, reject) => {
      // 不管有没有这个索引,都是删除成功的回调
      if (!this.dataBase.objectStoreNames.contains(this.dataSheetName)) {
        return resolve("未建该表")
      }
      const request = this.dataBase.transaction([this.dataSheetName], 'readwrite')
        .objectStore(this.dataSheetName)
        .delete(key)
      request.onsuccess = (e) => {
        console.info('dataBase数据删除成功', e)
        resolve()
      }
      request.onerror = (e) => {
        console.error('dataBase数据删除事务失败')
        reject(e.target.error)
      }
    })
  }
  // 删除数据库
  deleDataBase(dataBaseName) {
    return new Promise((resolve, reject) => {
      const DBDeleteRequest = window.indexedDB.deleteDatabase(dataBaseName);
      this.dataBase.close();
      DBDeleteRequest.onerror = (event) => {
        console.error("Error deleting database.");
        reject(event.target.error)
      };
      DBDeleteRequest.onsuccess = (event) => {
        console.log("Database deleted successfully", event);
        console.log(event.result); // should be undefined
        resolve(event.result)
      };
    })
  }


  // 删除表
  deleSheet(version) {
    return new Promise((resolve, reject) => {
      const request = window.indexedDB.open(this.dataBaseName, version);
      request.onerror = (event) => {
        // Handle errors.
        console.error(event.target.error)
        reject(event.target.error)
      };
      request.onsuccess = (event) => {
        this.dataBase.close();
        console.log('delet success')
      }
      request.onupgradeneeded = (event) => {
        this.dataBase = event.target.result;
        this.version = this.dataBase.version;
        this.dataBase.deleteObjectStore(this.dataSheetName);
        // this.dataBase.close(); 
        //删除之后不需要再关闭,否则会报错 DOMException: The connection was closed
        console.log(event.target, 'delete success')
        resolve(event)
      };
    })
  }

  destroy() {
    this.dataBase.close();
    console.log('数据库连接关闭')
  }
}
学新通

1.为什么初始化时,不执行open数据库?
2.为什么isReady()可传参,可不传参,什么情况适合传参?
3.为什么新增和修改数据时,需要先判断是否有表?
4.为什么删除和查询,不需要再次更新版本

接下来通过demo来解释

操作一张表

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>操作一张表</title>
    <style>
        .list {
            margin-top: 40px;
        }

        .box {
            border: 1px solid #ccc;
            padding: 50px;
        }
    </style>
</head>

<body>

    <div id="list">
        <div class="student box">
            <p>student表</p>
            <div>id: <input class="id" /></div>
            <br />

            <div>str: <input class="str" /></div>
            <br />
            <button class="add">新增数据</button>
            <button class="search">查找数据</button>
            <button class="romove">删除数据</button>
            <button class="update">更新数据</button>
            <button class="delete">删除表</button>
            <br />
        </div>
    </div>

    <br />

    <button id="deleteBase">删除库</button>

    <script type="module">
        import IndexedDB from '../util/indexedDB.js'
        // 不同数据库之间不需要open和关闭连接,也能够实现增删改查
        const studentbaseTable = {
            baseName: 'student', // 数据库名称
            sheetName: 'studentTable', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }] // 索引
        }

        const student = new IndexedDB(studentbaseTable)

        document.querySelector("#list .student .add").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            const str = document.querySelector("#list .student .str").value
            if(id !== "" && str !== "") {
                student.isReady().then(() => {
                    return student.add({
                        id,
                        str
                    })
                }).then(() => {
                    student.destroy()
                }).catch(e=> {
                    console.error(e)
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .student .search").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            if(id !== "") {
                student.isReady().then(() => {
                    return student.read(id)
                }).then(res => {
                    console.log('读取的数据为', res)
                    confirm('str: '  res.str)
                }).then(() => {
                    student.destroy()
                }).catch(e=> {
                    console.error(11, e)
                }).finally(() => {
                    console.log(22222)
                })
           
            } else {
                confirm("根据主键查找,主键不能为空")
            }
        }

        document.querySelector("#list .student .romove").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            if(id !== "") {
                student.isReady().then(() => {
                    return student.remove(id)
                }).then(res => {
                    confirm('删除成功')
                    student.destroy()
                }).catch(e => {
                    confirm('删除失败')
                })
           
            } else {
                confirm("根据主键删除,主键不能为空")
            }
        }
        
        document.querySelector("#list .student .update").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            const str = document.querySelector("#list .student .str").value
            if(id !== "" && str !== "") {
                student.isReady().then(() => {
                    return student.update({
                        id,
                        str
                    })
                }).then((res) => {
                    confirm('更新成功')
                    student.destroy()  
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .student .delete").onclick = () => {
            student.isReady().then(() => {
                return student.destroy()
            }).then(() => {
                return student.deleSheet(student.version   1)
            }).then(() => {
                confirm('删除成功')
            }).catch((e) => {
                confirm('删除表失败')
                console.error(e)
            })
            
        }


        document.querySelector("#deleteBase").onclick = () => {
            student.isReady().then(() => {
                student.deleDataBase('student').then(() => {
                    confirm('删除库成功')
                }).catch((e) => {
                    confirm('删除库失败')
                    console.error(e)
                })
            })
        }

    </script>
</body>

</html>

学新通

1.为什么初始化时,不执行open数据库?

通过这个demo,可以解释第一个疑问,没有执行open,是为了每次操作时就执行isReady()操作,也就是说只要进行数据表的增删改查再去新建这张表,这样就不存在,未建表时,进行表操作;如果这张表已经建好了,那自然而然不会执行onupgradeneeded回调
学新通

每次新增完这张数据表,就可以关闭数据库连接,只要不频繁的进行数据库的增删改查操作,我觉得就能关闭数据库连接,以免忘记关闭,同时也防止出现多次open数据库的情况

多次open数据库,但是没有及时close,会导致删除表操作时,卡死
删除表时,我们知道,需要版本号进行修改,且执行onupgradeneeded回调
也就是说多次open数据库,没有依次进行close,会导致真正的version发生改变时,也不执行onupgradeneeded回调

操作同一数据库不同表

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>同一个页面操作同一个数据库中的不同表</title>
    <style>
        .list {
            margin-top: 40px;
        }

        .box {
            border: 1px solid #ccc;
            padding: 50px;
        }
    </style>
</head>

<body>

    <div id="list">
        <div class="student box">
            <p>student表</p>
            <div>id: <input class="id" /></div>
            <br />

            <div>str: <input class="str" /></div>
            <br />
            <button class="add">新增数据</button>
            <button class="search">查找数据</button>
            <button class="romove">删除数据</button>
            <button class="update">更新数据</button>
            <button class="delete">删除表</button>
            <br />
        </div>
        <div class="teacher box">
            <p>teacher表</p>
            <div>id: <input class="id" /></div>
            <br />

            <div>str: <input class="str" /></div>
            <br />
            <button class="add">新增数据</button>
            <button class="search">查找数据</button>
            <button class="romove">删除数据</button>
            <button class="update">更新数据</button>
            <button class="delete">删除表</button>
            <br />
        </div>
    </div>

    <br />

    <button id="deleteBase">删除库</button>

    <script type="module">
        import IndexedDB from './indexedDB.js'
        // 不同数据库之间不需要open和关闭连接,也能够实现增删改查
        // 同一个数据库操作不同表格,需要等待上一个表操作close才能再次open下一个表,只有open之后才可以进行表格内容的增删改查
        // 注意数据库的版本version,添加操作和删除表操作,会导致version发生变化(每次操作数据表,都需要在open事触发版本更新)
        const studentbaseTable = {
            baseName: 'school', // 数据库名称
            sheetName: 'studentTable', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }] // 索引
        }
        const teacherbaseTable = {
            baseName: 'school', // 数据库名称
            sheetName: 'teacherTable', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }], // 索引
        }
        let teacher = null
        let maxVersion = null

        const student = new IndexedDB(studentbaseTable)
        student.isReady().then(() => {
            student.destroy()
            teacher = new IndexedDB(teacherbaseTable)
        }).then(() => {
            return teacher.isReady()
        }).then(() => {
            student.version  = teacher.version
            maxVersion = teacher.version
            console.log(maxVersion)
            teacher.destroy()
        })
 

        

        document.querySelector("#list .student .add").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            const str = document.querySelector("#list .student .str").value
            if(id !== "" && str !== "") {
                // teacher.destroy()
                student.open(maxVersion).then(() => {
                    return student.add({
                        id,
                        str
                    })
                    // 新增可能会改变版本号
                }).then(() => {
                    maxVersion = student.version

                    confirm('新增数据成功, id为'  id)
                    student.destroy()
                }).catch(() => {
                    confirm('新增数据失败, id为'  id)
                    student.destroy()
                })

            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .student .search").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            if(id !== "") {
                student.open(maxVersion).then(() => {
                    return student.read(id)
                }).then(res => {
                    console.log('读取的数据为', res)
                    confirm('str: '  res.str)
                    student.destroy()
                })
           
            } else {
                confirm("根据主键查找,主键不能为空")
            }
        }

        document.querySelector("#list .student .romove").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            if(id !== "") {
                student.open(maxVersion).then(() => {
                    return student.remove(id)
                }).then(res => {
                    confirm('student删除成功')
                    student.destroy()
                }).catch(e => {
                    confirm('student删除失败')
                })
           
            } else {
                confirm("根据主键删除,主键不能为空")
            }
        }

        document.querySelector("#list .student .update").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            const str = document.querySelector("#list .student .str").value
            if(id !== "" && str !== "") {
                // teacher.destroy();
                student.open(maxVersion).then(() => {
                    return student.update({
                        id,
                        str
                    })
                }).then(() => {
                    student.destroy()
                    confirm('更新成功')
                }).catch(() => {
                    confirm('更新失败')
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        // 进行增删改查之后删除操作很慢进行
        document.querySelector("#list .student .delete").onclick = () => {
            student.open(maxVersion).then(() => {
                return student.destroy()
            }).then(() => {
                return student.deleSheet(maxVersion 1)
            }).then(() => {
                maxVersion = student.version
                // student.destroy()
                confirm('student表删除成功')
            }).catch((e) => {
                confirm('删除表失败')
                console.error(e)
            })
        }

        document.querySelector("#list .teacher .add").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            const str = document.querySelector("#list .teacher .str").value
            if(id !== "" && str !== "") {
                console.log(maxVersion)
                teacher.open(maxVersion).then(() => {
                    return teacher.add({
                        id,
                        str
                    })
                    // 新增可能会改变版本号
                }).then(() => {
                    maxVersion = teacher.version
                    confirm('新增数据成功, id为'  id)
                    teacher.destroy()
                }).catch(() => {
                    confirm('新增数据失败, id为'  id)
                    teacher.destroy()
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .teacher .search").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            if(id !== "") {
                // student.destroy();
                teacher.open(maxVersion).then(() => {
                    return teacher.read(id)
                    // 新增可能会改变版本号
                    maxVersion = teacher.version
                }).then(res => {
                    console.log('读取的数据为', res)
                    confirm('str: '  res.str)
                }).then(() => {
                    teacher.destroy()
                })
           
            } else {
                confirm("根据主键查找,主键不能为空")
            }
        }

        document.querySelector("#list .teacher .romove").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            if(id !== "") {

                teacher.open(maxVersion).then(() => {
                    return teacher.remove(id)
                }).then(res => {
                    confirm('teacher删除成功')
                    teacher.destroy()
                }).catch(e => {
                    confirm('teacher删除失败')
                })
           
            } else {
                confirm("根据主键删除,主键不能为空")
            }
        }


        document.querySelector("#list .teacher .update").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            const str = document.querySelector("#list .teacher .str").value
            if(id !== "" && str !== "") {
                teacher.open(maxVersion).then(() => {
                    return teacher.update({
                        id,
                        str
                    })
                }).then(() => {
                    teacher.destroy()
                    confirm('更新成功')
                }).catch(() => {
                    confirm('更新失败')
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .teacher .delete").onclick = () => {
            teacher.open(maxVersion).then(() => {
                return teacher.destroy()
            }).then(() => {
                return teacher.deleSheet(maxVersion 1)
            }).then(() => {
                maxVersion = teacher.version
                confirm('teacher表删除成功')
            }).catch((e) => {
                confirm('删除表失败')
                console.error(e)
            })
        }

        document.querySelector("#deleteBase").onclick = () => {
            student.open(maxVersion).then(() => {
                student.deleDataBase('school').then(() => {
                    confirm('删除库成功')

                }).catch((e) => {
                    confirm('删除库失败')
                    console.error(e)
                })
            })
        }

    </script>
</body>

</html>
学新通

效果如图

学新通

2.为什么isReady()可传参,可不传参,什么情况适合传参?

这里可以解释这个疑问,同一个数据库中,多张表操作,会导致version版本号发生变化,所以需要页面维护这个版本号变量,当从一个表创建好之后,再创建另一个表时,需要升级版本号

所以当存在一个页面出现同一个数据库,多张表的情况就需要维护这个最高的版本号是多少了

当然,刷新页面这个版本号这个变量就会销毁,但是没关系,我们每次isReady()的时候,能够读取到最新的version变量

当一个页面操作同一个数据库中的不同表时,就需要维护version,所以也就这种情况需要传参,不然拿不到最新的version值,就会出现如下报错

dataBase打开报错 DOMException: The requested version (11) is less than the existing version (12).

并且删除数据库之后,下次依旧还能继续创建数据表再次进行数据添加和删除操作

学新通

操作不同数据库不同表


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>同一个页面操作不同数据库中的不同表</title>
    <style>
        .list {
            margin-top: 40px;
        }

        .box {
            border: 1px solid #ccc;
            padding: 50px;
        }
    </style>
</head>

<body>

    <div id="list">
        <div class="student box">
            <p>ss库中student表</p>
            <div>id: <input class="id" /></div>
            <br />

            <div>str: <input class="str" /></div>
            <br />
            <button class="add">新增数据</button>
            <button class="search">查找数据</button>
            <button class="romove">删除数据</button>
            <button class="update">更新数据</button>
            <button class="delete">删除表</button>
            <br />
        </div>
        <div class="teacher box">
            <p>tt库teacher表</p>
            <div>id: <input class="id" /></div>
            <br />

            <div>str: <input class="str" /></div>
            <br />
            <button class="add">新增数据</button>
            <button class="search">查找数据</button>
            <button class="romove">删除数据</button>
            <button class="update">更新数据</button>
            <button class="delete">删除表</button>
            <br />
        </div>
    </div>

    <br />

    <button id="deleteBase_ss">删除ss库</button>
    <button id="deleteBase_tt">删除tt库</button>

    <script type="module">
        import IndexedDB from '../util/indexedDB.js'
        // 不同数据库之间不需要open和关闭连接,也能够实现增删改查
        // 同一个数据库操作不同表格,需要等待上一个表操作close才能再次open下一个表,只有open之后才可以进行表格内容的增删改查
        // 注意数据库的版本version,添加操作和删除表操作,会导致version发生变化(每次操作数据表,都需要在open事触发版本更新)
        const studentbaseTable = {
            baseName: 'ss', // 数据库名称
            sheetName: 'studentTable', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }] // 索引
        }
        const teacherbaseTable = {
            baseName: 'tt', // 数据库名称
            sheetName: 'teacherTable', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }], // 索引
        }
        let teacher = null
        // let maxVersion = null

        const student = new IndexedDB(studentbaseTable)
        student.isReady().then(() => {
            student.destroy()
            teacher = new IndexedDB(teacherbaseTable)
        }).then(() => {
            return teacher.isReady()
        }).then(() => {
            teacher.destroy()
        })
 

        

        document.querySelector("#list .student .add").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            const str = document.querySelector("#list .student .str").value
            if(id !== "" && str !== "") {
                // teacher.destroy()
                student.isReady().then(() => {
                    return student.add({
                        id,
                        str
                    })
                    // 新增可能会改变版本号
                    // maxVersion = student.version
                }).then(() => {
                    confirm('新增数据成功, id为'  id)
                    student.destroy()
                }).catch(() => {
                    confirm('新增数据失败, id为'  id)
                    student.destroy()
                })

            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .student .search").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            if(id !== "") {
                student.isReady().then(() => {
                    return student.read(id)
                }).then(res => {
                    console.log('读取的数据为', res)
                    confirm('str: '  res.str)
                    student.destroy()
                }).catch(() => {
                    student.destroy()
                    confirm('查找数据失败')
                })
           
            } else {
                confirm("根据主键查找,主键不能为空")
            }
        }

        document.querySelector("#list .student .romove").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            if(id !== "") {
                student.isReady().then(() => {
                    return student.remove(id)
                }).then(res => {
                    confirm('student删除成功')
                    student.destroy()
                }).catch(e => {
                    student.destroy()
                    confirm('student删除失败')
                })
           
            } else {
                confirm("根据主键删除,主键不能为空")
            }
        }

        document.querySelector("#list .student .update").onclick = () => {
            const id = document.querySelector("#list .student .id").value
            const str = document.querySelector("#list .student .str").value
            if(id !== "" && str !== "") {
                // teacher.destroy();
                student.isReady().then(() => {
                    return student.update({
                        id,
                        str
                    })
                }).then(() => {
                    student.destroy()
                    confirm('更新成功')
                }).catch(() => {
                    student.destroy()
                    confirm('更新失败')
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        // 进行增删改查之后删除操作很慢进行
        document.querySelector("#list .student .delete").onclick = () => {
            student.isReady().then(() => {
                return student.destroy()
            }).then(() => {
                return student.deleSheet(student.version 1)
            }).then(() => {
                // maxVersion = student.version
                confirm('student表删除成功')
            }).catch((e) => {
                confirm('删除表失败')
                console.error(e)
            })
        }

        document.querySelector("#list .teacher .add").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            const str = document.querySelector("#list .teacher .str").value
            if(id !== "" && str !== "") {
                teacher.isReady().then(() => {
                    return teacher.add({
                        id,
                        str
                    })
                }).then(() => {
                    confirm('新增数据成功, id为'  id)
                    teacher.destroy()
                }).catch(() => {
                    confirm('新增数据失败, id为'  id)
                    teacher.destroy()
                })
                
            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .teacher .search").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            if(id !== "") {
                // student.destroy();
                teacher.isReady().then(() => {
                    return teacher.read(id)
                    // 新增可能会改变版本号
                    // maxVersion = teacher.version
                }).then(res => {
                    console.log('读取的数据为', res)
                    confirm('str: '  res.str)
                }).then(() => {
                    teacher.destroy()
                }).catch(() => {
                    teacher.destroy()
                    confirm('查找数据失败')
                })
           
            } else {
                confirm("根据主键查找,主键不能为空")
            }
        }

        document.querySelector("#list .teacher .romove").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            if(id !== "") {

                teacher.isReady().then(() => {
                    return teacher.remove(id)
                }).then(res => {
                    confirm('teacher删除成功')
                    teacher.destroy()
                }).catch(e => {
                    teacher.destroy()
                    confirm('teacher删除失败')
                })
           
            } else {
                confirm("根据主键删除,主键不能为空")
            }
        }


        document.querySelector("#list .teacher .update").onclick = () => {
            const id = document.querySelector("#list .teacher .id").value
            const str = document.querySelector("#list .teacher .str").value
            if(id !== "" && str !== "") {
                teacher.isReady().then(() => {
                    return teacher.update({
                        id,
                        str
                    })
                }).then(() => {
                    teacher.destroy()
                    confirm('更新成功')
                }).catch(() => {
                    teacher.destroy()
                    confirm('更新失败')
                })
            } else {
                confirm("主键和str不能为空")
            }
        }

        document.querySelector("#list .teacher .delete").onclick = () => {
            teacher.isReady().then(() => {
                return teacher.destroy()
            }).then(() => {
                return teacher.deleSheet(teacher.version 1)
            }).then(() => {
                // maxVersion = teacher.version
                // teacher.destroy();
                confirm('teacher表删除成功')
            }).catch((e) => {
                confirm('删除表失败')
                console.error(e)
            })
        }

        document.querySelector("#deleteBase_ss").onclick = () => {
            student.isReady().then(() => {
                student.deleDataBase('ss').then(() => {
                    confirm('删除ss库成功')

                }).catch((e) => {
                    confirm('删除ss库失败')
                    console.error(e)
                })
            })
        }

        document.querySelector("#deleteBase_tt").onclick = () => {
            teacher.isReady().then(() => {
                teacher.deleDataBase('tt').then(() => {
                    confirm('删除tt库成功')

                }).catch((e) => {
                    confirm('删除tt库失败')
                    console.error(e)
                })
            })
        }

    </script>
</body>

</html>

学新通

学新通

3.为什么新增和修改数据时,需要先判断是否有表?
因为当open表的回调还未执行完成, 可能页面一初始化完成,就立刻去查询页面是否存在某个数据, 当不存在这个数据时, 再去新增这个数据, 这张情况下, 就会出现未成功建表, 可以使用dataBase.objectStoreNames.contains(this.dataSheetName)判断

如果未建表, 就去操作数据表, 肯定是会报错的, 错误如下:
DOMException: Failed to execute ‘transaction’ on ‘IDBDatabase’: One of the specified object stores was not found.

数据库未open连接报错如下:
DOMException: Failed to execute ‘transaction’ on ‘IDBDatabase’: The database connection is closing.

4.为什么删除和查询,不需要再次更新版本
能够发现, 新增和更新, 本质都是调用add方法, 而add方法中, 判断未建表时, 会重新建表

学新通

原因其实也很简单, 新增数据, 那说明这个数据需要新增或者更新, 那这个时候未建表, 肯定会报错, 但是如果一直未建表, 就一直不能新增数据, 这就会导致功能出错了, 所以这里做了一点特殊处理.

初始化页面进行表操作


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  
  <div id="tableA">
    <p>tableA</p>
    <div>id: <input class="id" /></div>
    <br />

    <div>str: <input class="str" /></div>
    <br />
    <button class="add">新增数据</button>
    <button class="search">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="remove">删除表</button>
  </div>
  <div id="tableB">
    <p>tableB</p>
    <div>id: <input class="id" /></div>
    <br />

    <div>str: <input class="str" /></div>
    <br />
    <button class="add">新增数据</button>
    <button class="search">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="remove">删除表</button>
  </div>
  <script type="module">
    import IndexedDB from './indexedDB.js'
const studentbaseTable = {
            baseName: 'ss', // 数据库名称
            sheetName: 'tableA', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }] // 索引
        }
        const teacherbaseTable = {
            baseName: 'tt', // 数据库名称
            sheetName: 'tableB', // 数据表名称
            keyName: 'id', // 主键
            indexArr: [{ name: 'str' }], // 索引
        }
        let teacher = null
        // let maxVersion = null

        const student = new IndexedDB(studentbaseTable)
        student.isReady()
        .then(() => {
          return student.add({ id: 123, str: "test"})
        })
        .then(() => {
          return student.read(123)
        })
        .then(() => {
            student.destroy()
            teacher = new IndexedDB(teacherbaseTable)
        })
        .then(() => {
            return teacher.isReady()
        })
        .then(() => {
          return teacher.add({ id: 456, str: "asd"})
        })
        .then(() => {
          return teacher.read(456)
        })
        .then(() => {
            teacher.destroy()
        })
  </script>
</body>

</html>
学新通

学新通

最后附上本文的代码仓库:

https://gitee.com/bluelightsky/indexedBD
https://github.com/bluelightsky/indexedDB-demo

当然如果还需要满足阻塞等更加复杂的操作,推荐使用indexedDB的库,这里我推荐idb,参考文章中有介绍idb库使用的文章

参考文章:

英文:
https://hackernoon.com/use-indexeddb-with-idb-a-1kb-library-that-makes-it-easy-8p1f3yqq

中文: https://blog.csdn.net/ioriogami/article/details/128438731
https://zh.javascript.info/indexeddb#da-kai-shu-ju-ku

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhchbe
系列文章
更多 icon
同类精品
更多 icon
继续加载