Search
Write a publication
Pull to refresh

Comments 9

Почему нельзя хранить версии агрегатов в отдельной таблице: тип агрегата | ид агрегата | версия? Можно даже сделать эту таблицу нежурналируемой. Агрегаты ведь могут быть не персистентными и собираться из журнала действий. А команда на изменеие агрегата как раз должна хранить версию агрегата, котопую пытается изменить, чтобы сразу предупредить клиента о конфликте.

Вы пытаетесь модель предметной области материализовать один в один в инфраструктуре, что изначально выглядит порочно

Почему нельзя хранить версии агрегатов в отдельной таблице: тип агрегата | ид агрегата | версия? Можно даже сделать эту таблицу нежурналируемой. Агрегаты ведь могут быть не персистентными и собираться из журнала действий. А команда на изменеие агрегата как раз должна хранить версию агрегата, котопую пытается изменить, чтобы сразу предупредить клиента о конфликте.

Возможно я вас не так понял, но что нам это даёт? Изменение любой сущности внутри агрегата должно происходить через сам агрегат. Единственный теоретический плюс это то что в доменном объекте не будет инфраструктурного поля version. Зато за этот плюс придётся заплатить кастомной реализацией, тк из коробки оно работать не будет. Задача же была в том, чтобы автоматизировать версионность и исключить любое мануальное изменение версий.

Вы пытаетесь модель предметной области материализовать один в один в инфраструктуре, что изначально выглядит порочно

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

Тоже заметил коллизию. В домене вложенная сущность не должна знать о родителе, да. Однако ничто не мешает строить инфраструктуру способом, принятым именно для этой инфраструктуры. Аналогично, для приложения, вложенный контекст API должен иметь доступ к контексту родителя, но не родитель иметь доступ ко вложенному контексту, и дальше вглубь.

А нельзя использовать хеш от версий от частей агрегата, включая корень? Аля вычисляемое поле.

А зачем и что это изменит?

Простите, если туплю, но какой смысл от оптимистической блокировки, если используется @Transactional?

@Transactional, как и наличие транзакции в принципе, не решает проблему параллельных изменений данных, если только у вас не используются сериализуемые транзакции (а они, скорее всего, не используется, и не все базы данных их поддерживают) - по факту последовательное выполнение транзакций. Транзакция лишь гарантирует атомарность — либо все изменения будут сохранены, либо ни одно из них. Поэтому для любого уровня изолированности ниже сериализуемых транзакций возникают различные проблемы, которые решаются в том числе с помощью блокировок - оптимистичных или пессимистичных.

Приведу пример для уровня изолированности READ_COMMITTED (дефолтного для подавляющего большинства проектов с реляционными БД):

Предположим, у вас есть два аккаунта:

  • Account 1: balance 1000

  • Account 2: balance 1000

Два процесса параллельно пытаются изменить эти данные. Первый процесс читает баланс аккаунта 1, который равен 1000, снимает с него 100 и добавляет 100 на баланс аккаунта 2. Второй процесс также читает баланс аккаунта 1, который равен 1000, снимает с него 200 и добавляет 200 на баланс аккаунта 2 (будем считать что мы не используем атомарный инкремент/декремент).

Правильным результатом было бы:

  • Account 1: balance 700

  • Account 2: balance 1300

Но в зависимости от того, какой из процессов завершится первым, мы получим либо:

  • Account 1: balance 900

  • Account 2: balance 1100

Либо:

  • Account 1: balance 800

  • Account 2: balance 1200

Т.е. результаты одной из транзакций просто проигнорируются.

При этом с точки зрения каждой отдельной транзакции всё атомарно и правильно. Поэтому тут и нужны блокировки - либо пессимистичная (которая по факту просто не запустит вторую транзакцию пока не завершится первая), либо оптимистичная (которая отклонит вторую транзакцию и заставит её перевычитать данные, обновлённые первой транзакцией).

Причём в данном примере я описал проблему "потерянного обновления", тогда как в статье мы боремся с проблемой "ассиметрии записи", которая сложнее - она не игнорирует обновление одних и тех же объектов, но обновляя хоть и разные объекты приводит систему в невалидное состояние.

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

я бы предпочел увеличивать версию агрегата вручную, не люблю я магию под капотом

Sign up to leave a comment.

Articles