IndexedDB was introduced by Oracle and became popular very quickly. It's a Not Only SQL (NoSQL) database. The IndexedDB API is a more capable and far more complex API. IndexedDB has the following significant benefits:
One of the major disadvantages can be the difficulty in understanding it if you are coming from the world of rational databases. In IndexedDB, we can store a large amount of structured data, images, arrays, and whole objects; you just need to index them with a key. It follows the same origin policy, so we cannot access data across different domains. If you still use Web SQL database with your products, it's time to migrate to IndexedDB because the Web SQL database was deprecated by World Wide Web Consortium (W3C) in November 2010.
IndexedDB doesn't have any limits on a single database item's size, but it may impose a limit on each database's total items. We will use the asynchronous API because it works in most scenarios, including Web Workers. IndexedDB is a real database; therefore, before we use it, we need to specify a database schema, open a connection, and start using it to retrieve and update data within transactions. In this case, it gets very close to the Web SQL solution but is much simpler. Let's take a look at how we can use our example with IndexedDB. We will use the dart:indexed_db
package from the Dart SDK to work with IndexedDB. You can make a copy of the project from the Web SQL section, rename it shopping_cart_indexed_db
, and use IndexedDBStorageManager
instead of WebSQLStorageManager
. The code is as follows:
abstract class StorageManager { factory StorageManager() { if (IndexedDBStorageManager.supported) { return new IndexedDBStorageManager(); } else if (WebStorageManager.supported) { return new WebStorageManager(); } else { return new CookieStorageManager(); } } Future<String> getItem(key); Future setItem(key, value); Future removeItem(key); }
The preceding code shows the IndexedDBStorageManager
class. We constructed a special _getDatabase
method to retrieve an instance of the Database
class. As we mentioned earlier, before we use IndexedDB, we need to open the IndexedDB database. In the following code, we use the window.indexedDB.open
method to open our database. Next, we need to check whether the store exists in an objectStoreNames
array of the database. If it doesn't exist, we must close the database and open it again with a higher version number. Because this process is asynchronous, we create a new instance of the store
object inside the onUpgradeNeeded
listener. Each manipulation of the objects of the database happens inside a transaction. So, we will create a new transaction every time and return the ObjectStore
instance in the startTransaction
method. We will return the value of ObjectStore
via the getObject
method. To set an item in the database, we use the put
method of ObjectStore
. To remove the object from the store, just call the delete
method, as shown in the following code:
class IndexedDBStorageManager implements StorageManager { Database _database; static const SHOPPING = "SHOPPING"; static const PRODUCT = "PRODUCT"; static const TRANS_MODE = "readwrite"; Future _getDatabase(String dbName, String storeName) { if (_database == null) { return window.indexedDB.open(dbName).then((Database d) { _database = d; if (!_database.objectStoreNames.contains(storeName)) { _database.close(); return window.indexedDB.open(dbName, version: (d.version as int) + 1, onUpgradeNeeded: (e) { Database d = e.target.result; d.createObjectStore(storeName); }).then((Database d) { _database = d; return _database; }); } return _database; }); } else { return new Future.sync(() => _database); } } Future <ObjectStore> startTransaction(String storeName) { return _getDatabase(SHOPPING, PRODUCT) .then((Database database) { Transaction transaction = _database.transactionStore(storeName, TRANS_MODE); return transaction.objectStore(storeName); }); } Future <String> getItem(key) { return new Future.sync(() { return startTransaction(PRODUCT).then((ObjectStore store) { return store.getObject(key); }); }); } Future setItem(key, value) { return new Future.sync(() { return startTransaction(PRODUCT).then((ObjectStore store) { return store.put(value, key); }); }); } Future removeItem(key) { return new Future.sync(() { return startTransaction(PRODUCT).then((ObjectStore store) { return store.delete(key); }); }); } }
That's it. We can perform all manipulations on the data within ObjectStore
. The fact that the ObjectStore
class instance was returned via a Transaction
class indicates that all steps in the original one will be surrounded by a transaction. Let's expand the IndexedDB tree item in the Resources tab to see the SHOPPING database.
The version number of the database is 2. Now, choose the PRODUCT tree item and you will see that the same name contains our data.
When compared to Web SQL, IndexedDB is more simple and flexible. It uses indexes to access objects in the database within transactions.
3.144.30.178