1.介绍
webSQL
早期web浏览器器使用webSQL,采用的是关系型数据库,由于底层使用sqlLite,多个浏览器不好统一标准。
缺点:
- 查询效率低
- 前端需要学习sql语言
- 基于表的描述没有对象直观
- 读写都需要从表转化为json对象,或json转表操作
- 存储空间有限5m-25m
IndexedDB
基于NoSql的非关系型数据库,跟mongodb类似。基于json schema, 由于web比较流行的也是json格式,所以更倾向与非关系型数据库。
优点:
- 很适合前端或浏览器读取和存储
- 支持任意类型的对象结构
- 存储容量大,据说是当前浏览器可以使用容量的20%,即浏览器如果分配了1g,它就有200mb
缺点:
- 建立连接与操作事务,代码繁琐
- 都是异步回调,会有回调地狱问题
- 高级查询自己实现复杂
Dexie
基于IndexedDB的开源库
优点:
- 封装好了建立连接,事务,常用增删改。
- 简化的创建表特殊写法
- 封装的复杂的高级查询方法
- 支持索引
例子
1.IndexedDB
创建+新增
var request = window.indexedDB.open('myDB', '1') //创建或修改数据库版本, 第二个参数 为版本号
request.onerror = (event) => { //操作失败
console.log(event)
}
request.onsuccess = (event) => { //操作成功
var db = event.target.result
// 数据读取
var memberObjectStore = db.transaction('member').objectStore('member')
var userRequest = memberObjectStore.get(1)
userRequest.onsuccess = function (event) {
console.log(event.target.result)
}
}
request.onupgradeneeded = (event) => { //数据库连接后的回调方法
var db = event.target.result
//创建表
var objectStore = db.createObjectStore('member', { keyPath: 'id' }) //id为自增id
objectStore.createIndex('name', 'name', { unique: false }) //unique 设置为不唯一
objectStore.createIndex('gender', 'gender', { unique: false })
//新增
var data = [{ id: 1, name: 'jason', gender: '男'},
{ id: 2, name: 'bob', gender: '女'}, ]
objectStore.transaction.oncomplete = () => { //启动事务
var memberObjectStore = db.transaction('member', 'readwrite').objectStore('member')
data.forEach(data => { //遍历保存
memberObjectStore.add(data)
})
}
}
在谷歌浏览器-application - Storage - IndexedDB 查看保存的数据
查询
request.onsuccess = (event) => { //操作成功
var db = event.target.result
// 数据读取
var memberObjectStore = db.transaction('member').objectStore('member')
var userRequest = memberObjectStore.get(1)
userRequest.onsuccess = function (event) {
console.log(event.target.result)
}
}
删除
request.onsuccess = (event) => { //操作成功
var db = event.target.result
let id = 1
db.transaction(["member"],"readwrite") .objectStore("member") .delete(id);
}
修改
//let id = 1
var transaction = db.transaction(["member"],"readwrite");
var objectStore = transaction.objectStore("member");
var request = objectStore.get(id);
request.onsuccess = function(event){
request.result.name = '李四';
objectStore.put(request.result);
};
2.Dexie
创建
var db = new Dexie("MyDatabase");
db.version(1).stores({
friends: "++id, &uid, name, age, *tags", // ++id : 主键(自增) , &uid: 唯一id
gameSessions: "id, score"
});
更新版本
db.version(1).stores({
friends: "++id,name,age,*tags",
gameSessions: "id,score"
});
db.version(2).stores({
friends: "++id, [firstName+lastName], yearOfBirth, *tags", // Change indexes
gameSessions: null // Delete table
}).upgrade(tx => {
// Will only be executed if a version below 2 was installed.
return tx.table("friends").modify(friend => {
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
friend.birthDate = new Date(new Date().getFullYear() - friend.age, 0);
delete friend.name;
delete friend.age;
});
});
对象映射
class Friend {
// Prototype method
save() {
return db.friends.put(this); // Will only save own props.
}
// Prototype property
get age() {
return moment(Date.now()).diff (this.birthDate, 'years');
}
}
db.friends.mapToClass(Friend);
新增
await db.friends.add({name: "Josephine", age: 21});
await db.friends.bulkAdd([
{name: "Foo", age: 31},
{name: "Bar", age: 32}
]);
修改
await db.friends.put({id: 4, name: "Foo", age: 33});
await db.friends.bulkPut([
{id: 4, name: "Foo2", age: 34},
{id: 5, name: "Bar2", age: 44}
]);
await db.friends.update(4, {name: "Bar"});
await db.customers
.where("age")
.inAnyRange([ [0, 18], [65, Infinity] ])
.modify({discount: 0.5});
删除
await db.friends.delete(4);
await db.friends.bulkDelete([1,2,4]);
const oneWeekAgo = new Date(Date.now() - 60*60*1000*24*7);
await db.logEntries
.where('timestamp').below(oneWeekAgo)
.delete();
查询
const someFriends = await db.friends
.where("age").between(20, 25)
.offset(150).limit(25)
.toArray();
await db.friends
.where("name").equalsIgnoreCase("josephine")
.each(friend => {
console.log("Found Josephine", friend);
});
const abcFriends = await db.friends
.where("name")
.startsWithAnyOfIgnoreCase(["a", "b", "c"])
.toArray();
版本号
- 每次指定的版本都会记录到浏览器
- 浏览器什么时候都只能保存一份数据库
- 下次再重新指定版本号时,只有大于之前的版本号才能更新,否则更新失败。如原来是1.5, 现在改成1.1 则浏览器无法读取。(即如果以前有1.1版本,也不能再追溯了)
- upgrade方法会在版本号变化并且大于之前才会触发,如浏览器上次记录1.5,最新是1.7,则会触发更新方法,并且更新方法执行完后,把当前浏览器版本更新为 1.7
- 每次更新版本,都建议在更新方法执行清空表的数据。
DB.version(1.7).stores({
friends: "++id, &uid, name, age, *tags"
}).upgrade (trans => {
console.log('版本升级后,清空数据库内容成功,防止字段类型不一致')
trans.storeNames.forEach(o => {
trans[o].toCollection().delete() //清空数据
})
});
条件+分页查询
data(){
return {
form: {
content: "",
data: "",
view_path: "",
router_meta: "",
createTimeStart: "",
createTimeEnd: "",
user_code: "",
user_name: "",
}
}
},
methods: {
let dbTable
let queryObj = {}
try {
//设置from过滤条件
Object.keys(this.form).forEach(key => {
if(this.form[key] ) {
if(key != "createTimeStart" && key != "createTimeEnd"){
Object.assign(queryObj,{[key]:this.form[key]} )
}
}
})
let list = []
if (Object.keys(queryObj).length > 0) {
dbTable = dbTable.where(queryObj) //
}
let isfilterDate = false
if (this.form.createTimeStart || this.form.createTimeEnd) {
isfilterDate = true
}
const offset = (pageNo - 1) * pageSize
if (isfilterDate) { //当包含日期过滤时候的特殊处理
if (Object.keys(queryObj).length == 0) {
dbTable = dbTable.where("id").aboveOrEqual(0) //当没有过滤条件也要加入where 包装and能够正常执行
}
dbTable.and(item => {
if (!item.create_time) return true
let flag = this.form.createTimeStart ? item.create_time.getTime() > this.form.createTimeStart.getTime() : true
let flag2 = this.form.createTimeEnd ? item.create_time.getTime() < this.form.createTimeEnd.getTime() : true
return this.form.createTimeEnd && this.form.createTimeEnd ? flag && flag2 : (flag || flag2)
})
}
this.tables[this.moduleType].total = await dbTable.count()
list = await dbTable.offset(offset).limit(pageSize).toArray()
list = list.map((o) => {
o.create_time_show = formatDate(o.create_time)
return o
})
this.tables[this.moduleType].rows = list
} catch (error) {
this.$messageWarn("查询异常", error)
this.loading = false
}
}
indexedDB存储容量与地址
容量例子:
256GB 的硬盘,should remain available的值就是2GB,也就是浏览器临时存储空间是 254GB。这时候临时存储空间已经用了 4GB 了,这时候 IndexedDB 可用大小就是 50GB。
存放地址
windows:
C:\Users\xxxx\AppData\Local\Google\Chrome\User Data\Default\IndexedDB