Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

IndexedDB 基本命令文档

概述

IndexedDB 是浏览器提供的客户端存储 API,支持存储大量结构化数据,包括文件/二进制大型对象(blobs)。

基本概念

  • 数据库 (Database): 顶层容器,包含多个对象存储
  • 对象存储 (Object Store): 类似于关系数据库中的表
  • 事务 (Transaction): 操作的原子单位
  • 索引 (Index): 用于快速查找数据
  • 键路径 (Key Path): 对象中作为主键的属性

1. 数据库操作

1.1 打开数据库

// 打开数据库(如果不存在则创建)
const request = indexedDB.open('数据库名称', 版本号);

request.onsuccess = function(event) {
	const db = event.target.result;
	console.log('数据库连接成功');
};

request.onerror = function(event) {
	console.error('数据库连接失败:', event.target.error);
};

request.onupgradeneeded = function(event) {
	const db = event.target.result;
	// 数据库升级时执行
};

1.2 删除数据库

const deleteRequest = indexedDB.deleteDatabase('数据库名称');

deleteRequest.onsuccess = function() {
	console.log('数据库删除成功');
};

deleteRequest.onerror = function(event) {
	console.error('数据库删除失败:', event.target.error);
};

1.3 检查浏览器支持

if (!window.indexedDB) {
	console.log('当前浏览器不支持 IndexedDB');
} else {
	console.log('浏览器支持 IndexedDB');
}

2. 对象存储操作

2.1 创建对象存储

// 在 onupgradeneeded 事件中创建
request.onupgradeneeded = function(event) {
	const db = event.target.result;
	
	// 创建对象存储
	const objectStore = db.createObjectStore('存储名称', {
		keyPath: 'id',        // 主键字段
		autoIncrement: true   // 自动递增
	});
	
	// 或者使用外部键
	const objectStore2 = db.createObjectStore('存储名称2');
};

2.2 删除对象存储

// 在 onupgradeneeded 事件中删除
request.onupgradeneeded = function(event) {
	const db = event.target.result;
	
	if (db.objectStoreNames.contains('存储名称')) {
		db.deleteObjectStore('存储名称');
	}
};

3. 索引操作

3.1 创建索引

// 在创建对象存储时或 onupgradeneeded 中创建索引
const objectStore = db.createObjectStore('users', {
	keyPath: 'id',
	autoIncrement: true
});

// 创建索引
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
objectStore.createIndex('age', 'age', { unique: false });

3.2 删除索引

// 在 onupgradeneeded 事件中删除索引
request.onupgradeneeded = function(event) {
	const db = event.target.result;
	const transaction = event.target.transaction;
	const objectStore = transaction.objectStore('users');
	
	if (objectStore.indexNames.contains('索引名称')) {
		objectStore.deleteIndex('索引名称');
	}
};

4. 事务操作

4.1 创建事务

// 只读事务
const transaction = db.transaction(['存储名称'], 'readonly');

// 读写事务
const transaction = db.transaction(['存储名称'], 'readwrite');

// 多个存储的事务
const transaction = db.transaction(['存储1', '存储2'], 'readwrite');

4.2 事务事件

transaction.oncomplete = function() {
	console.log('事务完成');
};

transaction.onerror = function(event) {
	console.error('事务失败:', event.target.error);
};

transaction.onabort = function() {
	console.log('事务被中止');
};

5. 数据操作 (CRUD)

5.1 添加数据 (Create)

const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');

const user = {
	name: '张三',
	email: 'zhangsan@example.com',
	age: 25
};

const request = objectStore.add(user);

request.onsuccess = function(event) {
	console.log('数据添加成功,ID:', event.target.result);
};

request.onerror = function(event) {
	console.error('数据添加失败:', event.target.error);
};

5.2 读取数据 (Read)

按主键查询

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');

const request = objectStore.get(1); // 获取 ID 为 1 的记录

request.onsuccess = function(event) {
	const user = event.target.result;
	if (user) {
		console.log('找到用户:', user);
	} else {
		console.log('用户不存在');
	}
};

获取所有数据

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');

const request = objectStore.getAll();

request.onsuccess = function(event) {
	const users = event.target.result;
	console.log('所有用户:', users);
};

使用索引查询

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const index = objectStore.index('email');

const request = index.get('zhangsan@example.com');

request.onsuccess = function(event) {
	const user = event.target.result;
	console.log('通过邮箱找到用户:', user);
};

范围查询

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const index = objectStore.index('age');

// 年龄在 20-30 之间
const range = IDBKeyRange.bound(20, 30);
const request = index.getAll(range);

request.onsuccess = function(event) {
	const users = event.target.result;
	console.log('年龄在 20-30 之间的用户:', users);
};

5.3 更新数据 (Update)

const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');

const updatedUser = {
	id: 1,
	name: '李四',
	email: 'lisi@example.com',
	age: 28
};

const request = objectStore.put(updatedUser);

request.onsuccess = function() {
	console.log('用户更新成功');
};

5.4 删除数据 (Delete)

删除单条记录

const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');

const request = objectStore.delete(1); // 删除 ID 为 1 的记录

request.onsuccess = function() {
	console.log('用户删除成功');
};

清空所有数据

const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');

const request = objectStore.clear();

request.onsuccess = function() {
	console.log('所有数据已清空');
};

6. 游标操作

6.1 基本游标

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');

const request = objectStore.openCursor();

request.onsuccess = function(event) {
	const cursor = event.target.result;
	
	if (cursor) {
		console.log('当前记录:', cursor.value);
		cursor.continue(); // 移动到下一条记录
	} else {
		console.log('遍历完成');
	}
};

6.2 索引游标

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const index = objectStore.index('name');

const request = index.openCursor();

request.onsuccess = function(event) {
	const cursor = event.target.result;
	
	if (cursor) {
		console.log('用户:', cursor.value);
		cursor.continue();
	}
};

6.3 范围游标

const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const index = objectStore.index('age');

const range = IDBKeyRange.lowerBound(18); // 年龄 >= 18
const request = index.openCursor(range);

request.onsuccess = function(event) {
	const cursor = event.target.result;
	
	if (cursor) {
		console.log('成年用户:', cursor.value);
		cursor.continue();
	}
};

7. 键范围 (IDBKeyRange)

7.1 创建键范围

// 等于特定值
const exactRange = IDBKeyRange.only(25);

// 大于等于
const lowerRange = IDBKeyRange.lowerBound(18);

// 大于(不包含边界)
const lowerOpenRange = IDBKeyRange.lowerBound(18, true);

// 小于等于
const upperRange = IDBKeyRange.upperBound(65);

// 小于(不包含边界)
const upperOpenRange = IDBKeyRange.upperBound(65, true);

// 范围(包含边界)
const boundRange = IDBKeyRange.bound(18, 65);

// 范围(不包含边界)
const boundOpenRange = IDBKeyRange.bound(18, 65, true, true);

8. 错误处理

8.1 常见错误类型

request.onerror = function(event) {
	const error = event.target.error;
	
	switch (error.name) {
		case 'QuotaExceededError':
			console.error('存储空间不足');
			break;
		case 'InvalidStateError':
			console.error('数据库状态无效');
			break;
		case 'ConstraintError':
			console.error('约束错误(如唯一索引冲突)');
			break;
		case 'DataError':
			console.error('数据错误');
			break;
		default:
			console.error('未知错误:', error);
	}
};

9. Promise 封装

9.1 封装为 Promise

function openDB(name, version) {
	return new Promise((resolve, reject) => {
		const request = indexedDB.open(name, version);
		
		request.onsuccess = () => resolve(request.result);
		request.onerror = () => reject(request.error);
		request.onupgradeneeded = (event) => {
			// 数据库升级逻辑
		};
	});
}

function addData(db, storeName, data) {
	return new Promise((resolve, reject) => {
		const transaction = db.transaction([storeName], 'readwrite');
		const store = transaction.objectStore(storeName);
		const request = store.add(data);
		
		request.onsuccess = () => resolve(request.result);
		request.onerror = () => reject(request.error);
	});
}

10. 最佳实践

10.1 版本管理

const DB_VERSION = 1;

function upgradeDB(event) {
	const db = event.target.result;
	const oldVersion = event.oldVersion;
	const newVersion = event.newVersion;
	
	if (oldVersion < 1) {
		// 创建初始结构
		const userStore = db.createObjectStore('users', {
			keyPath: 'id',
			autoIncrement: true
		});
		userStore.createIndex('email', 'email', { unique: true });
	}
	
	if (oldVersion < 2) {
		// 添加新的索引或存储
	}
}

10.2 错误重试机制

async function retryOperation(operation, maxRetries = 3) {
	for (let i = 0; i < maxRetries; i++) {
		try {
			return await operation();
		} catch (error) {
			if (i === maxRetries - 1) throw error;
			console.warn(`操作失败,正在重试 (${i + 1}/${maxRetries}):`, error);
			await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
		}
	}
}

10.3 数据备份和恢复

// 导出数据
async function exportData(db, storeName) {
	const transaction = db.transaction([storeName], 'readonly');
	const store = transaction.objectStore(storeName);
	const request = store.getAll();
	
	return new Promise((resolve, reject) => {
		request.onsuccess = () => {
			const data = request.result;
			const json = JSON.stringify(data, null, 2);
			resolve(json);
		};
		request.onerror = () => reject(request.error);
	});
}

// 导入数据
async function importData(db, storeName, jsonData) {
	const data = JSON.parse(jsonData);
	const transaction = db.transaction([storeName], 'readwrite');
	const store = transaction.objectStore(storeName);
	
	// 清空现有数据
	await store.clear();
	
	// 导入新数据
	for (const item of data) {
		await store.add(item);
	}
}

11. 性能优化

  • 使用事务批量操作数据
  • 合理设计索引,避免过多索引
  • 使用游标遍历大量数据
  • 避免在主线程进行大量数据操作
  • 适当使用 Web Workers 处理复杂操作

12. 兼容性注意事项

  • IE 10+ 支持 IndexedDB
  • Safari 在私有模式下有限制
  • 某些移动浏览器可能有存储限制
  • 建议使用 polyfill 提升兼容性

About

Demo: how to use indexedDB

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages