Журнал изменений базы данных
От: afkos  
Дата: 11.02.20 10:14
Оценка:
Добрый день!

Разрабатываем такую специфическую систему средних размеров для управления данными, для промышленности, в основном.
Столкнулись с необходимостью иметь в БД какой-то журнал со сведениями об изменениях различных сущностей,
чтобы внешние системы с которыми настроена интеграция (штатная или силами клиента) могли понимать какие сущности удалены, изменены, добавлены в системе, для того чтобы их подтянуть себе.

Первое что приходит в голову — табличка в бд:
TABLE EventLog (eventId, eventType, entityId, ... )
— Храним только тип события и идентификатор сущности, сами изменения не хранятся
— Источник изменений (БД) добавляет в неё события в тригерах или еще как-то, внутри транзакций — таким образом мы сразу имеем атомарность изменений.
— Читатели вычитывают новые записи по eventId.
— Читателей может быть несколько, поэтому записи из таблицы при чтении не удаляются — чтобы другие читатели могли подключиться с любой точки синхронизации и получить изменения.
— Удалять записи предполагается в сервисной функции за заведомо устаревшие периоды времени.

С записью кажется все в порядке, а вопрос — как правильно из него читать:

Допустим есть внешняя система — назовем её читатель,
она по расписанию или по событию вычитывает все новые записи из таблицы
select .. from EventLog where eventId > @lastEventId -- СУБД у нас версионник, мы получим все новые записи, кроме еще не зафиксированных транзакций.
где @lastEventId — это идентификатор последней записи, которую он прочитал до этого (по сути @lastEventId — точка синхронизации)

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

НО при этом возможна следующая ситуация:

в EventLog Max(eventId) = 10
Транзакция А — добавляет запись eventId = 11
Транзакция Б — добавляет запись eventId = 12
Транзакция Б — фиксирует транзакцию
Читатель:
— выполняет запрос select from EventLog where eventId > 10,
— получает запись eventId = 12,
— запоминает @lastEventId = 12
Транзакция А — фиксирует транзакцию (eventId = 11)

Проблема: Читатель больше никогда не узнает о записи с eventId = 11. т.к его @lastEventId = 12

Читать из EventLog с ожиданием на блокировке в этом сценарии — крайне нежелательно.
Использовать внешнюю очередь в текущей архитектуре затруднительно

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

Можно ли что-то сделать в предложенной схеме?
Буду очень благодарен любым советам!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.