Браузерное хранилище на базе IndexedDB изначально проектировалось как
система с изолированными базами данных, каждая из которых существует в
собственном пространстве имён. Библиотека Dexie.js полностью наследует
эту модель и рассматривает каждую базу как отдельный экземпляр
Dexie.
Ключевой момент: один экземпляр Dexie = одна база данных
IndexedDB. Следовательно, работа с несколькими базами сводится к
управлению несколькими экземплярами Dexie в одном
приложении.
Каждая база определяется уникальным именем при создании экземпляра:
import Dexie from "dexie";
const userDB = new Dexie("user_database");
userDB.version(1).stores({
profiles: "id, name, email"
});
const logsDB = new Dexie("logs_database");
logsDB.version(1).stores({
events: "++id, type, timestamp"
});
В этом примере создаются две независимые базы:
user_database — хранение пользовательских данныхlogs_database — хранение событий и логовКаждая база имеет собственные версии схем, транзакции и индексы.
Разделение на несколько баз данных применяется в архитектурах, где требуется строгая изоляция доменов данных.
Разные доменные области приложения могут иметь несовместимые модели данных. Например:
Разделение снижает риск конфликтов миграций и упрощает поддержку схем.
Каждая база имеет собственный versioning:
const analyticsDB = new Dexie("analytics");
analyticsDB.version(1).stores({
hits: "++id, url, createdAt"
});
analyticsDB.version(2).stores({
hits: "++id, url, createdAt, userId"
});
Миграции одной базы не влияют на другие, что позволяет обновлять части системы независимо.
При росте приложения разделение баз упрощает:
Практика использования фабрики позволяет контролировать создание и повторное использование экземпляров:
import Dexie from "dexie";
const dbRegistry = new Map();
export function getDB(name) {
if (dbRegistry.has(name)) {
return dbRegistry.get(name);
}
const db = new Dexie(name);
dbRegistry.set(name, db);
return db;
}
Использование:
const userDB = getDB("user_database");
const logsDB = getDB("logs_database");
Такой подход предотвращает дублирование соединений и облегчает тестирование.
Каждая база может иметь собственный singleton:
import Dexie from "dexie";
let instance = null;
export function getUserDB() {
if (instance) return instance;
instance = new Dexie("user_database");
instance.version(1).stores({
profiles: "id, name, email"
});
return instance;
}
IndexedDB не поддерживает транзакции, охватывающие несколько баз данных. Это означает:
Для согласованности применяется паттерн компенсации:
async function updateUserAndLog(user) {
try {
await userDB.profiles.put(user);
await logsDB.events.add({
type: "USER_UPDATED",
timestamp: Date.now()
});
} catch (e) {
await userDB.profiles.delete(user.id);
throw e;
}
}
auth_dbprofile_dbcache_dbТакое разделение удобно при модульной архитектуре frontend-приложений.
Отдельная база может использоваться для:
Каждая база обновляется независимо:
const cacheDB = new Dexie("cache");
cacheDB.version(1).stores({
responses: "url, data"
});
cacheDB.version(2).stores({
responses: "url, data, ttl"
});
Однако при наличии взаимозависимых данных возникает проблема синхронизации версий между базами, требующая централизованного контроля миграций на уровне приложения.
const user = await userDB.profiles.get(1);
await cacheDB.responses.put({
url: "/profile/1",
data: user
});
Можно использовать внутреннюю шину событий:
function emitChange(event) {
window.dispatchEvent(new CustomEvent("db-change", { detail: event }));
}
userDB.profiles.hook("creating", (primKey, obj) => {
emitChange({ type: "create", table: "profiles", obj });
});
Каждая база IndexedDB создает собственные:
При большом количестве баз возможны накладные расходы:
Рекомендуется ограничивать число баз и объединять данные, если нет жесткой необходимости в разделении.
Разные базы не разделяют индексы, поэтому при необходимости кросс-доменных запросов возникает дублирование:
Это повышает скорость чтения, но увеличивает объем хранилища.
const testUserDB = new Dexie("test_user_db");
const testLogsDB = new Dexie("test_logs_db");
Перед каждым тестом базы очищаются:
await testUserDB.delete();
await testLogsDB.delete();
Для тестирования часто создаются временные базы с уникальными именами:
const db = new Dexie(`temp_db_${Date.now()}`);
Одновременные операции в нескольких базах могут приводить к:
Отсутствие общей транзакционности приводит к ситуациям:
При изменении логики приложения:
Это требует координации миграций на уровне приложения.
Каждый модуль приложения получает собственную базу:
Каждая предметная область полностью изолирована, включая:
Инициализация нескольких баз должна быть контролируемой:
const dbs = {
user: new Dexie("user_db"),
logs: new Dexie("logs_db"),
cache: new Dexie("cache_db")
};
dbs.user.version(1).stores({
profiles: "id, name"
});
dbs.logs.version(1).stores({
events: "++id, type"
});
dbs.cache.version(1).stores({
responses: "url"
});
Такой подход формирует явную границу ответственности и упрощает сопровождение системы.