数据库存储html代码-python 数据转html库
IndexedDB 是一种 API,用于在客户端存储大量结构化数据,并在这些数据上使用索引进行高性能检索。 尽管 DOM 存储对于存储少量数据非常有用,但它无法存储大量结构化数据。 IndexedDB 提供了这样的解决方案。
IndexedDB 为同步和异步访问提供单独的 API。 同步 API 仅供 Web Workers 在内部使用,但尚未被任何浏览器实现。 Web Worker 内部和外部都可以使用异步 API。 所以现在能用的基本都是异步API,因为在h5手机项目中使用了indexedDB来存储app相关的数据,所以写一些例子供参考:
1.异步API
首先了解什么是异步API:异步API方法被调用后会立即返回,不会阻塞调用线程。 要异步访问数据库,需要调用window对象的indexedDB属性的open()方法。 该方法返回一个IDBRequest对象(IDBOpenDBRequest); 异步操作通过触发 IDBRequest 对象上的事件与调用程序通信。 IDBOpenDBRequest 接口定义了几个重要的属性:
数据库调用成功、失败、升级的方法可以通过不同的回调函数来实现。 让我们从打开数据库开始。
2.创建(打开)数据库
在最简单的例子中,创建一个数据库至少需要两个参数:数据库名称和数据库版本。 为了方便起见,我们创建一个简单的数据库管理类:
class DBmanager {
//数据库管理类的构造函数,包含两个构造参数,数据库名称和数据库版本,数据库版本如果不指定默认为1;
constructor(DBname, DBversion) {
this.DBname = DBname;
this.DBversion = DBversion || 1;
this.currentDB = null; //当前数据库
}
//打开(没有创建过则创建)数据库的方法
openDB() {
//调用API打开数据库
var request = window.indexedDB.open(this.DBname, this.DBversion);
//打开数据库失败的回调
request.onerror = function (e) {
console.log(e.currentTarget.error.message);
}.bind(this);
//打开数据库成功的回调
request.onsuccess = function (e) {
this.currentDB = e.target.result;
console.log(this.currentDB.name + ' database is already opened!');
}.bind(this);
//数据库升级的回调
request.onupgradeneeded = function (e) {
console.log('database version is already upgrade to '+this.DBversion);
}.bind(this);
}
}
onupgradeneeded 回调将在两种情况下被调用:
当数据库首次创建时数据库版本发生变化
在调用onupgradeneeded的时候,onupgradeneeded会在onsuccess和onerror之前执行,因为打开数据库的时候,先检查是否有版本变化,如果有版本变化,先升级数据库再打开,这样我们就可以实现数据库onupgradeneeded 中的升级方法。
为了看到具体的执行效果,我们来运行一下:
window.onload = function () {
var db = new DBmanager('testDB', 1);
db.openDB();
}
在chromium浏览器中运行,按F12,可以看到APPlication选项下的indexedDB中多了一个新创建的数据库“testDB”,version为1,log为建库成功时回调打印的日志打开,说明建库成功。 打开:
3.关闭并删除数据库
关闭数据库可以直接调用数据库对象的close方法。 我们在DBmanager中添加一个成员函数:
//关闭数据库的方法
closeDB() {
this.currentDB.close();
console.log(this.currentDB.name + ' database is already closed!');
}
要删除数据库,请使用 indexedDB 对象的 deleteDatabase 方法。 我们在DBmanager中添加一个成员函数:
//删除数据库的方法
deleteDB() {
window.indexedDB.deleteDatabase(this.DBname);
console.log(this.DBname + ' database is already deleted!');
}
由于是异步API,不保证在调用closeDB方法时一定会通过openDB获取到DB对象,所以我们这里使用setTimeout进行延时,保证获取到DB对象后关闭数据库。
window.onload = function () {
var db = new DBmanager('testDB', 1);
db.openDB();
setTimeout(function () {
db.closeDB();
db.deleteDB();
}, 500);
}
运行后在控制台可以看到输出日志
4.对象存储
在关系型数据库中,我们以表的形式存储数据,但indexedDB中并没有表的概念,而是对象存储。 一个数据库中可以有多个object store,一个object store相当于一张表,可以存储多种数据类型,每种数据类型对应一个Key值。 我们可以指定一个字段作为Key值,或者自动生成Key值,或者指定。 例如,在下面的例子中,我们在onupgradeneed 中新建一个名为“students”的对象存储,并指定“id”作为键值。
request.onupgradeneeded = function (e) {
console.log('database version is already upgrade to '+this.DBversion);
this.currentDB = e.target.result;
if(!this.currentDB.objectStoreNames.contains('students')){
//指定一个键为主键
this.currentDB.createObjectStore('students',{keyPath:"id"});
//指定为主键自增模式
//db.createObjectStore('students',{autoIncrement: true});
}
}.bind(this);
5.交易
关系数据库中也有事务的概念,但是这里的事务和关系数据库中的事务不一样。 在indexedDB中,在对数据库中的数据进行增删改查之前,需要先启动一个事务。 在事务中,指定需要操作的那些对象存储。 获取到对应的对象库后,我们就可以对获取到的对象库进行操作了。 这里我们在DBmanager中添加一个成员函数,根据object store的名称启动一个事务,并获取对应的object store:
//根据storeName获取对应store的方法
getStoreByName(storeName){
var transaction = this.currentDB.transaction(storeName,'readwrite');
return transaction.objectStore(storeName);
}
其中,交易有三种模式:
只读:只读,不能修改数据库数据,可并发读写:可进行readwrite,读写操作 版本变更:verionchange
6.添加数据
我们在调用createObjectStore方法时创建了一个名为students的对象存储,并指定主键为id。 现在我们可以向商店添加数据,我们准备一些数据:
//名为students的ObjectStore
const datas=[{
id:11,
name:"zhangsan",
age:24
},{
id:12,
name:"lisi",
age:30
},{
id:13,
name:"wangwu",
age:26
},{
id:14,
name:"zhaoliu",
age:26
}];
然后我们添加一个用于向DBmanager添加数据的成员函数:
//添加数据的方法
addData(storeName,data){
var store = this.getStoreByName(storeName);
for(var i = 0; i<data.length ; i++){
store.add(data[i]);
}
}
转移:
window.onload = function () {
var db = new DBmanager('testDB', 2);
db.openDB();
setTimeout(function () {
db.addData('students',datas);
db.closeDB();
}, 500);
}
打开chromium浏览器,我们可以看到我们在indexedDB中添加的数据:
7.删除数据
删除一条数据:
//删除一条数据(根据主键key(id))
deleteDataByKey(storeName,key){
var store = this.getStoreByName(storeName);
store.delete(key);
}
删除所有数据:
//删除整个ObjectStore的数据
deleteAllData(storeName){
var store = this.getStoreByName(storeName);
store.clear();
}
是否删除成功可以运行后在chromium浏览器中验证
8.更新数据
这里写一个根据key值更新age值的方法供参考:
//根据键值修改数据
updateDataByKey(storeName,key,age){
var store = this.getStoreByName(storeName);
var request = store.get(key);
request.onsuccess = function (e) {
var student = e.target.result;
student.age = age;
store.put(student);
}
}
转移:
window.onload = function () {
var db = new DBmanager('testDB', 1);
db.openDB();
setTimeout(function () {
db.updateDataByKey('students',11,25);
db.closeDB();
}, 500);
}
这样,store store id为11的数据对应的age值就变成了25。
9.查找数据
根据id值查询对应的姓名和年龄:
//根据键值查询数据
getDataByKey(storeName,key){
var store = this.getStoreByName(storeName);
var request = store.get(key);
request.onsuccess = function (e) {
var student = e.target.result;
console.log('key is '+key+',name:'+student.name+',age:'+student.age);
}
}
10.索引
以上介绍了indexedDB的基本使用。 接下来介绍indexedDB的索引。 索引的优点是可以快速定位数据,提高查找速度。indexedDB中有两种索引,一种是自增的int值,由indexedDB自己定义; 另一个是keyPath,这个是我们自己指定的,下面重点介绍keyPath索引的使用
11.索引
可以在创建object store的时候指定索引,使用object store的createIndex创建索引,有三个参数
例子:我们为name和age这两个属性创建对应的索引,onupgradeneeded可以这样写:
request.onupgradeneeded = function (e) {
console.log('database version is already upgrade to '+this.DBversion);
this.currentDB = e.target.result;
if(!this.currentDB.objectStoreNames.contains('students')){
//指定一个键为主键
var store = this.currentDB.createObjectStore('students',{keyPath:"id"});
//指定为主键自增模式
//db.createObjectStore('students',{autoIncrement: true});
store.createIndex('nameIndex','name',{unique:true});
store.createIndex('ageIndex','age',{unique:false});
}
}.bind(this);
索引建立成功后,可以在chromium中看到对应的索引:
12.根据索引查询数据
//根据索引查询数据
getDataByIndex(storeName,indexName,index){
var store = this.getStoreByName(storeName);
var indexStore = store.index(indexName);
var request = indexStore.get(index);
request.onsuccess = function (e) {
var student = e.target.result;
console.log('index is '+index+',id:'+student.id+',age:'+student.age);
}
}
比如我们要查询nameIndex为zhangsan的数据:
db.getDataByIndex('students','nameIndex','zhangsan');
13.游标游标
indexedDB中索引和游标的使用密不可分。 如果查询结果是多条数据,我们可以使用游标来遍历查询结果:
//通过游标获取所有数据
fetchStoreByCurser(storeName) {
var store = this.getStoreByName(storeName);
var request = store.openCursor();
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var currentStudent = cursor.value;
console.log('currentStudent:' + currentStudent.name);
//curson.contine()会使游标下移,直至没有数据则返回undefined
cursor.continue();
}
}
}
14.游标与索引联合查询
//通过游标和index查询
getMultipleData(storeName, indexName, age) {
var store = this.getStoreByName(storeName);
var indexStore = store.index(indexName);
var request = indexStore.openCursor(IDBKeyRange.only(age));
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var student = cursor.value;
console.log(student.name);
cursor.continue();
}
};
}
比如我们要查询年龄为26岁的所有数据:
db.getMultipleData('students', 'ageIndex', 26);
15.指定光标范围
index.openCursor()/index.openKeyCursor() 方法在不传参的情况下会获取对象存储的所有记录。 像上面的例子,我们可以过滤搜索
可以使用key range来限制游标中值的范围,将其作为第一个参数传递给openCursor()或openKeyCursor()
例如:
//指定游标范围查询
getDataBetweenTwoData(storeName,indexName,start,end,isStartOpen,isEndOpen) {
var store = this.getStoreByName(storeName);
var indexStore = store.index(indexName);
//true是不包括,false是包括
var request = indexStore.openCursor(IDBKeyRange.bound(start, end, isStartOpen, isEndOpen));
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var student = cursor.value;
console.log(student.name);
cursor.continue();
}
}
}
比如查询年龄在24到30之间的所有数据,包括24,不包括30,可以这样查:
db.getDataBetweenTwoData('students','ageIndex',24,30,false,true);
16.获取商店中存储条目的总数
getStoreDataCount(storeName) {
var store = this.getStoreByName(storeName);
var req = store.count();
req.onsuccess = function (e) {
console.log(e.target.result);
}
}
17、获取店铺中满足多个条件的条目总数
多条件前提下的查询,首先要有多条件查询的索引。 由于数据有限,我们会创建一个由name和age组成的多条件索引,在onupgradeneeded中,为'students:创建一个索引:
store.createIndex('myIndex',['name','age'],{unique:false});
然后我们写一个函数:
//获取store中满足多个条件的条目的总数
getDataCountByMultiCondition(storeName,indexName,condition) {
var store = this.getStoreByName(storeName)
var indexStore = store.index(indexName);
var request = indexStore.openCursor(IDBKeyRange.only(condition));
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var student = cursor.value;
console.log(student.id);
cursor.continue();
}
}
}
然后查询名为“lisi”且年龄为30的所有数据:
db.getDataCountByMultiCondition('students','myIndex',['lisi',30]);
18.如何获取返回值
在上面的例子中,我们获取到的数据在函数中是用到用日志打印出结果的,但是在实际中,我们需要获取到其他地方的查询结果数据库存储html代码,但是在请求的回调中,我们无法得到结果直接作为函数返回值返回给函数调用者,这里也使用callback来传递获取的值。 例如,我们重写获取商店存储商品总数的方法:
//获取某个store中存储条目的总数
fetchStoreDataCount(storeName,callback) {
var count = 0;
var store = this.getStoreByName(storeName);
var req = store.count();
req.onsuccess = function (e) {
count = e.target.result;
callback(count);
}
}
其中callback是一个回调函数,我们用callback传递返回值:
db.fetchStoreDataCount('students',function (count) {
console.log(count);
});
这样数据库存储html代码,我们就可以使用回调来传递任何查询得到的值。 你可以尝试用这个方法把上面查询到的所有数据都传过去。 你只需要在调用的地方实现回调函数即可。
19.其他
可能有同学注意到,在openDB的方法中,在请求的onsuccess、onerror、onupgradeneeded之后添加了.bind(this)。 原因如下:
因为我是用ES6中的类来实现整个DBmanager的,但是js中的this和java中的this并不完全一样,指的是当前对象,比如这里:request的onsuccess,onerror和onupgradeneeded回调函数这里不指的是DBmanager对象,但是为了请求,所以为了改变DBmanager要改变onsuccess中的成员变量的值,指向DBmanager的this值被绑定到onsuccess。
另外,在DBmanager的实现过程中,为了方便,没有使用get和set方法来获取和设置成员变量的值,很多地方需要进一步改进。 这里只是给大家一个简单的参考。 欢迎批评指正。
20.源代码
indexedDB.html:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<script>
class DBmanager {
//数据库管理类的构造函数,包含两个构造参数,数据库名称和数据库版本,数据库版本如果不指定默认为1;
constructor(DBname, DBversion) {
this.DBname = DBname;
this.DBversion = DBversion || 1;
this.currentDB = null; //当前数据库
}
//打开(没有创建过则创建)数据库
openDB() {
//调用API打开数据库
var request = window.indexedDB.open(this.DBname, this.DBversion);
//打开数据库失败的回调
request.onerror = function (e) {
console.log(e.currentTarget.error.message);
}.bind(this);
//打开数据库成功的回调
request.onsuccess = function (e) {
this.currentDB = e.target.result;
console.log(this.currentDB.name + ' database is already opened!');
}.bind(this);
//数据库升级的回调,此回调在数据库版本变化时和数据库第一次创建时执行
request.onupgradeneeded = function (e) {
console.log('database version is already upgrade to ' + this.DBversion);
this.currentDB = e.target.result;
if (!this.currentDB.objectStoreNames.contains('students')) {
//指定一个键为主键
var store = this.currentDB.createObjectStore('students', {keyPath: "id"});
//指定为主键自增模式
//db.createObjectStore('students',{autoIncrement: true});
store.createIndex('nameIndex', 'name', {unique: false});
store.createIndex('ageIndex', 'age', {unique: false});
store.createIndex('myIndex', ['name', 'age'], {unique: false});
}
}.bind(this);
}
//关闭数据库
closeDB() {
this.currentDB.close();
console.log(this.currentDB.name + ' database is already closed!');
}
//删除数据库
deleteDB() {
window.indexedDB.deleteDatabase(this.DBname);
console.log(this.DBname + ' database is already deleted!');
}
//根据storeName获取对应store的方法
getStoreByName(storeName) {
var transaction = this.currentDB.transaction(storeName, 'readwrite');
return transaction.objectStore(storeName);
}
//添加数据
addData(storeName, data) {
var store = this.getStoreByName(storeName);
for (var i = 0; i < data.length; i++) {
store.add(data[i]);
}
}
//根据键值修改数据
updateDataByKey(storeName, key, age) {
var store = this.getStoreByName(storeName);
var request = store.get(key);
request.onsuccess = function (e) {
var student = e.target.result;
student.age = age;
store.put(student);
}
}
//根据键值查询数据
getDataByKey(storeName, key) {
var store = this.getStoreByName(storeName);
var request = store.get(key);
request.onsuccess = function (e) {
var student = e.target.result;
console.log('key is ' + key + ',name:' + student.name + ',age:' + student.age);
}
}
//根据索引查询数据
getDataByIndex(storeName, indexName, index) {
var store = this.getStoreByName(storeName);
var indexStore = store.index(indexName);
var request = indexStore.get(index);
request.onsuccess = function (e) {
var student = e.target.result;
console.log('index is ' + index + ',id:' + student.id + ',age:' + student.age);
}
}
//通过游标获取所有数据
fetchStoreByCurser(storeName) {
var store = this.getStoreByName(storeName);
var request = store.openCursor();
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var currentStudent = cursor.value;
console.log('currentStudent:' + currentStudent.name);
//curson.contine()会使游标下移,直至没有数据则返回undefined
cursor.continue();
}
}
}
//通过游标和index查询
getMultipleData(storeName, indexName, age) {
var store = this.getStoreByName(storeName);
var indexStore = store.index(indexName);
var request = indexStore.openCursor(IDBKeyRange.only(age));
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var student = cursor.value;
console.log(student.name);
cursor.continue();
}
};
}
//指定游标范围查询
getDataBetweenTwoData(storeName, indexName, start, end, isStartOpen, isEndOpen) {
var store = this.getStoreByName(storeName);
var indexStore = store.index(indexName);
//true是不包括,false是包括
var request = indexStore.openCursor(IDBKeyRange.bound(start, end, isStartOpen, isEndOpen));
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var student = cursor.value;
console.log(student.name);
cursor.continue();
}
}
}
//获取某个store中存储条目的总数
getStoreDataCount(storeName) {
var store = this.getStoreByName(storeName);
var req = store.count();
req.onsuccess = function (e) {
console.log(e.target.result);
}
}
//获取store中满足多个条件的条目的总数
getDataCountByMultiCondition(storeName, indexName, condition) {
var store = this.getStoreByName(storeName)
var indexStore = store.index(indexName);
var request = indexStore.openCursor(IDBKeyRange.only(condition));
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
var student = cursor.value;
console.log(student.id);
cursor.continue();
}
}
}
//获取某个store中存储条目的总数
fetchStoreDataCount(storeName, callback) {
var count = 0;
var store = this.getStoreByName(storeName);
var req = store.count();
req.onsuccess = function (e) {
count = e.target.result;
callback(count);
}
}
}
//名为students的ObjectStore
const datas = [{
id: 11,
name: "zhangsan",
age: 24
}, {
id: 12,
name: "lisi",
age: 30
}, {
id: 13,
name: "wangwu",
age: 26
}, {
id: 14,
name: "zhaoliu",
age: 26
},];
window.onload = function () {
var db = new DBmanager('testDB', 4);
db.openDB();
setTimeout(function () {
// db.getDataCountByMultiCondition('students','myIndex',['lisi',30]);
// db.getDataBetweenTwoData('students','ageIndex',24,30,false,true);
// db.getMultipleData('students', 'ageIndex', 26);
// db.fetchStoreByCurser('students');
// db.getDataByIndex('students','nameIndex','zhangsan');
// db.addData('students',datas);
// db.getDataByKey('students',11);
db.fetchStoreDataCount('students', function (count) {
console.log(count);
});
db.closeDB();
// db.deleteDB();
}, 500);
}
script>
body>
html>