This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021

1, the preface

As the capabilities of the browser continue to increase, more and more sites are considering storing large amounts of data on the client side, which can be accessed faster than a back-end interface. Existing browser storage schemes are not suitable for storing large amounts of data. Cookie size is not more than 4KB, and each request will be sent to the server, LocalStorage in 2.5 ~ 10MB direct, different browsers, storage size is not the same, and does not provide search function, also can not build a custom index, webSQL you can learn about, Since the Web SQL Database specification has been deprecated, the official documentation makes it clear that the underlying webSQL specification uses SQLite’s SQL dialect, which is not acceptable as a standard, and that each browser has its own implementation, as IE has done. Finally, and most importantly, a client-side scheme for storing large amounts of data: IndexedDB.

2. WebSQL subtotal

(1) Create a database

var db = openDatabase('person'.1.'person'.0) First parameter: name of the database second parameter: version number third parameter: Remarks Third parameter: size. The default value is5M
Copy the code

Create a table

db.transaction(tx => { 
   tx.executeSql('create table if not exists student(id unique, name)')})Copy the code

(3) Insert two data

db.transaction(tx => { 
   tx.executeSql('insert into student (id, name) value(? ,?) '[1.'Joe']);         
   tx.executeSql('insert into student (id, name) value (? ,?) '[2.'bill']);
})
Copy the code

(4) Query data

db.transaction(tx => {
   tx.executeSql('select * from student', [], (tx, res) => {
      let rows = res.rows;
      let len = rows.length
      for (var i=0; i< len, i++) {
         console.log(rows.item(i))
      }
   })
})
Copy the code

conclusion

  • WebSQL standard no longer updated, relational database, underlying SQLite
  • Chrome has a capacity of 5M and supports different pages with the same domain name
  • The version parameter is used for control. If the version opened is inconsistent with the existing version, an error is reported

3, with IndexedDB storage

IndexedDB is not a relational database and does not support SQL queries. It is more similar to a NoSQL database and is a transactional key-value front-end database. Most of its APIS are asynchronous.

  • Key-value pair storage

    IndexedDB uses an internal object repository to store data. All types of data can be stored directly, including JavaScript objects. Each data record has a corresponding primary key, which is unique and cannot be repeated

  • asynchronous

    IndexedDB operates without locking the browser, and users can still perform other operations. All of its apis operate asynchronously, which is designed to be zero to prevent large data reads and writes from slowing web page performance.

  • Support transactions

    Support for transactions means that, in the process of operation (add, delete, alter, look), if any asynchronous failure, the entire transaction is cancelled, the database is rolled back to the state before the transaction occurred, and there is no case that only part of the data is overwritten.

  • The same-origin restrictions

    Each database corresponds to its domain name. Web pages can only access databases under their own domain names, but not cross-domain databases

  • Large storage space

    IndexedDB typically has no less than 250 megabytes of storage space, or even no upper limit

1. Common concepts of IndexedDB

IndexedDB is a complex API that abstracts different entities into object interfaces.

* IDBDatabase object * Object repository IDBObjectStore object, Similar to relational database table * index IDBIndex object * transaction IDBTransaction object * operation request IDBRequest object * pointer IDBCursor object * primary key set IDBKeyRange objectCopy the code

Note: Only one version of an IndexedDB database exists at a time. If you want to change the structure of a database, you can only change the version of the database. Each database contains several object repositories. Multiple tables can be created for each database, and indexes can be built in the object repository to speed up the retrieval of data.

Note: Transactions

Data records are read, written, and deleted through transactions, and the transaction object provides three callback events

onerror onsuccess onupgradeneeded

2. Operation process

(1) Open the database

The first step to using IndexedDB is to open the database, using the indexeddb.open () method

var IDBRequest = window.indexedDB.open(databaseName, version)
Copy the code

First parameter: database name, which will be created if the database does not exist

Second parameter: indicates the version of the database. If omitted, the default is the current version. The default is: 1

The result indexeddb.open () method returns an IDBRequest object that processes the opened database through three different events: Error, Success, and upgradenneeded.

  • The onError event indicates that the database fails to be opened

    IDBRequeset.onerror = funciton(event) {
       console.log('Database open failed')}Copy the code
  • The onSuccess event indicates that the database is opened successfully

    var db
    IDBRequeset.onsuccess = function(event) {
       db = IDBRequeset.result
       console.log('Database opened successfully')}Copy the code
  • Upgrade needed event Indicates that a database upgradeneeded event will happen if the specified version number is greater than the actual version needed of the database

    var db;
    IDBRequeset.onupgradeneeded = function(event) {
        db = event.target.result
    }
    Copy the code

(2) Create a database

Creating a database is the same operation as opening a database. If the required open database does not exist, it needs to be created as a new database. This is an upgradeneeded event which triggers onupgradeneneeded and all subsequent operations are carried out in this callback

IDBRequest.onupgradeneeded = function(event) {
  db = event.target.result // Get the database instance
  // Check whether the table exists
  var objectStore;
  if(! db.objectStoreNames.contains('person')) {
    objectStore = db.createOjbectStore('person', { keyPath: 'id'}}})Copy the code

IndexedDB can also be set to the primary key automatically without an ID

objectStore = db.createOjbectStore('person', { autoIncrement: true })
Copy the code

The next step is to create the index directly

objectStore.createIndex('name'.'name', { unique: false})
Copy the code

(3) New data

New data refers to the writing of data records to the object repository, which needs to be done through transactions

function add() {
   var request = db.transaction(['person'].'readwrite')
           .objectStore('person')
           .add({ id: 1.name: 'zlm'.age: 24.email: '[email protected]'});
       request.onsuccess = function (event) {
            console.log('Write data successfully', event)
        };
       request.onerror = function (event) {
            console.log('Write data failed',event)
       }
  }
Copy the code

To add data, create a new transaction, using the Transaction () method. The first parameter specifies the table name. The second parameter specifies the operation mode, read-only or read-write. After the new transaction is completed, use the objectStore() method to get the objectStore, the table object, with one parameter: the table name. Finally, a record is written to the table using the add() method of the table object

(4) Read data

Reading data is also done through transactions

function read() {
       var transaction = db.transaction['person'];
       var objectStore = transaction.objectStore('person')
       var request = objectStore.get(1)
           request.onerror = function (event) {
               console.log('Failed to read transaction',event)
           }
           request.onsuccess = function (event) {
               if (request.result) {
                   console.log('Name', + request.result.name)
                   console.log('Age', + request.result.age)
                   console.log('Email', + request.result.email)
               } else {
                   console.log('Data record not acquired')}console.log('Read success event', event)
           }
    }
Copy the code

(5) Traverse the data

Walk over all the data in the table using the pointer object IDBCursor

function readAll() {
     var objectStore = db.transaction('person').objectStore('person')
         objectStore.opneCursor().onsuccess = function(event) {
           var cursor = event.target.result
           if (cursor) {
             console.log('ID: ' + cursor.key)
             console.log("Name: " + cursor.value.name)
             console.log("Age: " + cursor.value.age)
             console.log('Email: ' + cursor.value.name)
             cursor.continue()
           } else {
             console.log('No more data has been obtained')}}}Copy the code

(6) Update data

Update the data using the idbobject.put () method

function update() {
  var request = db.transaction(['person'].'readwrite')
           .objectStore('person')
           .put({ id: 1.name: 'four zhang'.age: 32.email: '[email protected]'})
      request.onsuccess = function (event) {
           console.log('Data updated successfully', event)
      }
      request.onerror = function (event) {
           console.log('No more data has been obtained', event)
      }
  }
Copy the code

(7) Delete data

Use the idBobjectStore.delete () method

function remove() {
        var request = db.transaction(['person'])
                        .objectStore('person')
                        .delete(1)
            request.onsuccess = function (event) {
                console.log('Data deleted successfully', event)
            } 
    }
Copy the code

(8) Index

The point of an index is that it allows you to search any field, get data records from any field, and if you don’t build an index, only search primary keys

  • When creating a new table, add an index to the name field

    objectStore.createIndex('name'.'name', {unique: false})
    Copy the code
  • Find the corresponding data record by name

    var transaction = db.transaction(['person'].'readonly')
    var store = transaction.objectStore('person')
    var index = store.index('name')
    var request = index.get('zlm')
    request.onsuccess = function(event) {
       var result = event.target.result
       if(result) {
           console.log('Get data')}else {
           console.log('No data obtained')}}Copy the code

Here is your own test, Demo.js

/** * IDBDatabase database * IDBObjectStore object repository * IDBIndex index * IDBTransaction transaction * IDBRequest operation request * IDBCursor pointer * IDBKeyRang Primary key collection */
/ /! Open the database
var db;
var request =  window.indexedDB.open('myIndexDB');
    request.onerror =  function (event) {
        console.log('Database opening error', event)
    }
    request.onsuccess = function (event) {
        db = request.result
        console.log('Database opened successfully', event)
    }
    // If the specified version is larger than the actual version of the database, a database upgrade event may occur
    request.onupgradeneeded = function (event) {
        db = event.target.result
        console.log('Database Upgrade Event')
        var objectStore;
        if(! db.objectStoreName.contains('person')) {
            objectStore = db.createObjectStore('person', { keyPath: 'id'})
            objectStore.createIndex('name'.'name', { unique: true})
            objectStore.createIndex('email'.'email', { unique: true})}console.log(objectStore)
    }
console.log(db)

// Add data
function add() {
        var request = db.transaction(['person'].'readwrite')
                      .objectStore('person')
                      .add({ id: 1.name: 'Joe'.age: 24.email: '[email protected]'});
            request.onsuccess = function (event) {
                console.log('Write data successfully', event)
            };
            request.onerror = function (event) {
                console.log('Write data failed',event)
            }
    }

// Read data
    function read() {
       var transaction = db.transaction['person'];
       var objectStore = transaction.objectStore('person')
       var request = objectStore.get(1)
           request.onerror = function (event) {
               console.log('Failed to read transaction',event)
           }
           request.onsuccess = function (event) {
               if (request.result) {
                   console.log('Name', + request.result.name)
               } else {
                   console.log('Data record not acquired')}console.log('Read success event', event)
           }
    }

    // Use the IDBCursor object to move over all data in the table
    function readAll() {
        var objectStore = db.transaction('person').objectStore('person')
            objectStore.opneCursor().onsuccess = function(event) {
                 var cursor = event.target.result
                 if (cursor) {
                     console.log('ID: ' + cursor.key)
                     console.log("Name: " + cursor.value.name)
                     cursor.continue()
                 } else {
                     console.log('No more data has been obtained')}}}// Update data
    function update() {
        var request = db.transaction(['person'].'readwrite')
                        .objectStore('person')
                        .put({ id: 1.name: 'four zhang'.age: 32.email: '[email protected]'})
            request.onsuccess = function (event) {
                console.log('Data updated successfully', event)
            }
            request.onerror = function (event) {
                console.log('No more data has been obtained', event)
            }
    }

// Delete data
    function remove() {
        var request = db.transaction(['person'])
                        .objectStore('person')
                        .delete(1)
            request.onsuccess = function (event) {
                console.log('Data deleted successfully', event)
            } 
    }
Copy the code

4, actual combat operation

After a bit of daydreaming, I found that indexedDB had been encapsulated by a number of people, and when I compared it, I found:

Dexie.js encapsulates IndexedDB with simple syntax, making it easy to write code quickly

Conclusion: Dexie.js is a wrapper around indexedDB for the browser, making it easier to manipulate indexedDB.

(1) Why use Dexie.js

  • Native IndexedDB operations are performed in callbacks
  • All native operations require the constant creation of transactions to determine the presence of tables and indexes
  • Native operations do not support batch operations
  • Native errors need to be handled in each failure callback

Compared with Dexie. js, it supports chain call, convenient index definition, and supports multi-value index and composite index, and perfect documentation

Dexie official website document

(1) Installation

npm  install dexie
Copy the code

or

<script src="https://unpkg.com/dexie@latest/dist/dexie.js"></script>
Copy the code

(2) Use

Step 1: Get a database instance

import Dexie from 'dexie';
var db = new Dexie('Database name')
Copy the code

Step 2: Define the table structure

db.version(1).stores({
    users: "++id, name, age, emial".students: "++id, &username".books: "id, author, name, *categories"
})
Copy the code

Note: 1 If the attribute is preceded by a ++ match, it is an increment of the primary key

Note: 2 if the field is preceded by &, it is a unique index

Note: 3 If the field is preceded by *, it indicates that the field is a multi-value index

Conform to the describe
++ Automatically increments the primary key
& Only the primary key
* Multi-value index
+ The composite index

(3) Query

All WHERE clause operators can be used to query multi-item index objects,

  • Above () returns all records where the value of the specified field is greater than a certain value

  • AboveOrEqual () returns all records where the specified field value is greater than or equal to a certain value

  • AnyOf () returns the records contained in the given array in the data set

  • Below () returns all records where the value of the specified field is less than a value

  • BelowOrEqual () returns all records with a specified field value less than or equal to a certain value

  • Between () returns the record between the two

  • The equals () equal to zero

    You can refer to the official website for details

    Dexie API documentation

Here is demo.html for your own test

<! doctypehtml>
<html>
  <head>
      <script src="https://unpkg.com/dexie@latest/dist/dexie.js"></script>
      <script>
          // Create an instantiation object
        async function openIDB() {
            var db = new Dexie("MyDatabase");
                db.version(1).stores({
                    tasks: '++id, name, age, email'
                });
                // Add data
                db.tasks.add({
                    name: 'zlm'.age:22.email: '[email protected]'
                })
                db.tasks.add({
                    name: 'Joe'.age: 18.email: '[email protected]'
                })
                // Modify the data
                db.tasks.put({
                    id: 2.name: 'bill'.age: 100.email: ' '
                })
                // Query data
                console.log('Query first data')
                const oldTask = await db.tasks.get(1)
                console.log(oldTask)
                // Query all ids greater than 0
                const allTask = await db.tasks.where('id').above(0).toArray()
                console.log('Query all data')
                console.log(allTask)
                // Get data in batches
                const bulkgetData = await db.tasks.bulkGet([1.2.3.4])
                console.log('Batch data')
                console.log(bulkgetData)
                // db.tasks.clear()
        }
        openIDB()  
      </script>
  </head>
</html>
Copy the code