Архитектура IndexedDB: базы данных, хранилища, транзакции

В основе IndexedDB лежит модель локального клиентского хранения данных, организованная вокруг концепции базы данных, содержащей набор именованных хранилищ объектов. Каждая база данных представляет собой изолированное пространство, в котором данные структурируются и управляются независимо от других баз, доступных в пределах одного origin (домен, протокол, порт).

База данных в IndexedDB является версионной сущностью. Любое изменение структуры — добавление или удаление хранилищ, создание индексов, изменение схемы — требует увеличения версии базы. При открытии базы с новой версией инициируется процесс миграции структуры, во время которого происходит конфигурация новых объектов хранения.

Ключевой особенностью архитектуры выступает асинхронная модель взаимодействия. Операции открытия, чтения, записи и модификации выполняются неблокирующим образом, что исключает влияние на основной поток выполнения JavaScript.

Хранилища объектов (Object Stores)

Хранилища объектов представляют собой фундаментальную единицу организации данных внутри базы IndexedDB. Каждое хранилище можно рассматривать как аналог таблицы в реляционных системах, однако с принципиально иной моделью структуры данных.

В отличие от таблиц SQL, хранилища не требуют фиксированной схемы строк. Каждый объект, сохраняемый в store, может иметь произвольную структуру, если он сериализуем. Единственное обязательное условие — наличие ключа, который однозначно идентифицирует запись.

Ключ может задаваться явно или формироваться автоматически с использованием ключевого пути (keyPath) либо генератора автоинкремента. Поддерживаются как простые ключи (строки, числа), так и составные (compound keys), формируемые из нескольких свойств объекта.

Хранилища также могут содержать индексы, обеспечивающие быстрый доступ к данным по альтернативным ключам. Индекс представляет собой специализированную структуру, которая поддерживает поиск по значению конкретного поля объекта без необходимости полного перебора записей.

Особенность индексов IndexedDB заключается в том, что они обновляются автоматически при изменении данных в связанном хранилище, что обеспечивает консистентность данных без дополнительной логики со стороны разработчика или библиотеки-обертки.

Индексы и организация доступа к данным

Индексы формируют дополнительный слой структуры внутри object store. Каждый индекс строится на основе одного или нескольких свойств объекта и хранит отсортированные ссылки на записи.

Основные характеристики индексов:

  • поддержка уникальности значений (unique index)
  • возможность хранения неуникальных значений
  • поддержка множественных ключей через multiEntry режим
  • автоматическая синхронизация с изменениями данных

Индексы позволяют выполнять запросы с ограничением по диапазону значений. Используются операторы сравнения, такие как lower bound, upper bound и их комбинации. Это обеспечивает эффективную фильтрацию без необходимости загрузки всего набора данных в память.

В архитектуре IndexedDB индексы не являются вторичной надстройкой над данными в традиционном смысле, а встроенной частью структуры хранения, что делает их высокоэффективными при масштабных наборах данных.

Транзакционная модель

Транзакции являются центральным механизмом обеспечения целостности данных в IndexedDB. Любая операция чтения или записи выполняется внутри транзакции, которая определяет контекст доступа к одному или нескольким хранилищам.

Транзакция обладает несколькими ключевыми свойствами:

  • атомарность: все операции внутри транзакции либо завершаются успешно, либо откатываются
  • изоляция: параллельные транзакции не конфликтуют при корректном разделении режимов доступа
  • ограниченность по времени жизни: транзакции автоматически завершаются после выполнения всех запросов

Существуют три основных режима транзакций:

  • readonly — доступ только для чтения, допускает параллельное выполнение нескольких транзакций
  • readwrite — разрешает модификацию данных, блокирует соответствующие хранилища на время выполнения
  • versionchange — используется исключительно при изменении структуры базы данных

Режим versionchange является единственным способом модификации схемы. Во время его выполнения база данных блокируется для других операций, что обеспечивает безопасную миграцию структуры.

Транзакции в IndexedDB работают на основе событийной модели. Каждая операция внутри транзакции представляет собой запрос, который может завершиться успехом или ошибкой. Успешное завершение всех запросов приводит к автоматическому коммиту транзакции, тогда как любая ошибка вызывает откат.

Область видимости транзакций и блокировки

Транзакции в IndexedDB имеют строго определённую область действия, ограниченную набором object stores, указанных при их создании. Это позволяет минимизировать блокировки и повышать параллелизм.

Блокировка реализуется на уровне хранилищ. Readonly-транзакции могут выполняться параллельно, если не конфликтуют по объектам доступа. Readwrite-транзакции требуют эксклюзивного доступа к затронутым хранилищам, что предотвращает конкурентные модификации данных.

Такая модель блокировок обеспечивает баланс между производительностью и консистентностью, позволяя выполнять большое количество параллельных операций без нарушения целостности данных.

Жизненный цикл базы данных

Открытие базы данных инициирует процесс установления соединения с хранилищем IndexedDB. В случае отсутствия базы она создаётся автоматически. Если версия базы отличается от текущей, запускается процесс обновления структуры.

Жизненный цикл включает несколько фаз:

  1. открытие соединения
  2. проверка версии
  3. запуск миграции (при необходимости)
  4. активация базы
  5. выполнение транзакций

Во время миграции используется транзакция специального типа versionchange, в рамках которой происходит создание и модификация object stores и индексов.

После завершения инициализации база переходит в активное состояние и становится доступной для выполнения пользовательских транзакций.

Согласованность и модель хранения

IndexedDB использует модель хранения, основанную на сериализации объектов. Данные сохраняются в виде структурированных клонируемых объектов, что позволяет хранить сложные структуры, включая вложенные объекты, массивы и бинарные данные.

Согласованность данных обеспечивается комбинацией транзакционной модели и атомарных операций записи. Каждая операция либо полностью фиксируется, либо полностью откатывается, исключая частично записанные состояния.

Особое значение имеет порядок выполнения операций внутри транзакции. Запросы выполняются последовательно в рамках одного контекста, однако разные транзакции могут выполняться конкурентно при отсутствии конфликтов по хранилищам.

Роль Dexie.js в абстракции архитектуры IndexedDB

Dexie.js выступает надстройкой над низкоуровневым API IndexedDB, предоставляя более выразительную и структурированную модель взаимодействия с базами данных.

На уровне архитектуры Dexie.js:

  • инкапсулирует создание и управление версиями базы
  • упрощает работу с транзакциями через декларативные API
  • предоставляет удобный синтаксис для запросов и индексов
  • автоматизирует обработку ошибок и откатов транзакций

При этом базовая модель IndexedDB сохраняется неизменной: Dexie.js не заменяет транзакционную систему и структуру object stores, а лишь упрощает их использование.

В контексте архитектуры IndexedDB Dexie.js можно рассматривать как слой оркестрации, который преобразует декларативные операции в цепочки запросов и транзакций, соответствующих нативной модели браузера.

Версионирование и миграции структуры

Изменения структуры базы данных реализуются через механизм версий. Каждая версия описывает состояние схемы на определённый момент времени. При переходе между версиями выполняется последовательность миграционных операций.

Типичные изменения схемы включают:

  • добавление новых хранилищ
  • удаление устаревших хранилищ
  • создание или модификацию индексов
  • изменение ключевых путей

Миграции выполняются строго последовательно в рамках versionchange транзакции. Это гарантирует, что структура базы всегда находится в согласованном состоянии и не подвергается частичным обновлениям.

Dexie.js упрощает описание миграций через цепочку версий, где каждая новая версия описывает изменения относительно предыдущей, сохраняя прозрачность эволюции схемы данных.

Взаимодействие компонентов архитектуры

Архитектура IndexedDB формируется взаимодействием трёх основных уровней:

  • база данных как контейнер
  • object stores как структурные единицы хранения
  • транзакции как механизм управления доступом и целостностью

Эти компоненты тесно связаны между собой и образуют единый механизм локального хранения данных в браузере. База данных определяет границы контекста, хранилища определяют структуру данных, транзакции обеспечивают безопасное выполнение операций.

Dexie.js интегрируется в эту модель, не нарушая её фундаментальных принципов, а лишь предоставляя более высокоуровневый интерфейс, соответствующий архитектуре IndexedDB.