172 похожих чатов

Кто-То может подсказать как можно сделать атомарно вот такую вещь? UPDATE

users SET balance=(SELECT SUM(amount) FROM transactions WHERE user_id=?)
Я же верно понимаю, что тут 2 запроса и если кто-то удалил параллельно из таблицы транзакций после того как в этом запросе посчиталась сумма, то я сохраню невалидный баланс.
Кроме блокировок можно это решить? Я знаю, что если мы будем запускать перерасчет после каждой операции изменения в таблицы transactions, то получим eventual consistency и баланс так или иначе будет верный. Мне бы понять можно ли просто запросом sql такой кейс решить

15 ответов

11 просмотров

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

А как Вы собираетесь поддерживать в валидном состоянии баланс, если только не из приложения?

Кстати, почему бы не использовать триггеры на таблице transactions, которые будут автоматически обновлять поле balance в таблице users ? В случае триггеров счётчик не должен сбиваться.

Andrei Ilinskii
Кстати, почему бы не использовать триггеры на табл...

Вообще я бы через CTE соединил запросы вставки новых данных в transactions и обновление счётчика, чтобы не усложнять структуру базы.

Evgeny-Kungurov Автор вопроса
Andrei Ilinskii
Кстати, почему бы не использовать триггеры на табл...

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

Evgeny Kungurov
Я ниразу их не юзал. Я разработчик который постоян...

Давай без триггеров вариант с CTE посмотрим. WITH data(user_id, amount) AS ( -- входящие параметры SELECT :user_id, :amount ), insert AS ( INSERT INTO transactions SELECT * FROM data ) UPDATE users SET balance = balance + data.amount FROM data WHERE users.user_id = data.user_id Чем не нравится?

Evgeny Kungurov
Надо обмозговать)

С триггерами по-сути тоже самое будет, просто часть с update уедет в триггер. Если задача держать поле balance в постоянном соответствии с суммой amount по таблице transactions, то вставка в транзакции и обновление счётчика должны идти в одной транзакции, по очевидным причинам )

Запросы всегда работают атомарно, а Вам тут нужно изоляция. К примеру, на уровне изоляции serializable это делается тривиально. Понятия "после / до" для параллельных транзакций не имеют прямого отношения к consistency, кстати.

Andrei Ilinskii
Кстати, почему бы не использовать триггеры на табл...

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

Она и так атомарная. Баланс в любом случае на какой-то момент будет валидным -- и перестанет быть валидным сразу после этого момента. Более того, время, в течение которого этот баланс был валидным -- можэт быть строго 0, что не отменяет того, что значение поля balance после коммита соответствует балансу на какой-то момент в прошлом. Вопрос как сделать, чтобы этот баланс не менялся -- это другой вопрос. И ключевое здесь -- сколько вы хотите чтобы он не менялся и зачем вам это нужно.

Evgeny Kungurov
Я ниразу их не юзал. Я разработчик который постоян...

Если Вам важен результат этих транзакций — почитали бы Вы какой-то "фундаментальный" учебник про основные принципы ACID, честное слово. А то потом приходится (лично мне много приходилось) искать косяки в транзакциях и как-то устранять "кашу" в БД после "блокировщиков". ;(

Evgeny-Kungurov Автор вопроса
Yaroslav Schekin
Если Вам важен результат этих транзакций — почитал...

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

Evgeny Kungurov
Есть пример? А то тонна инфы в инете, а толку не т...

Пример учебника, в смысле? Я сходу не помню... ну вот "Database system concepts", например. > у которых есть в компании DBA Заниматься такими вещами — вообще не дело DataBase Administrator. Это базовые знания, умения и ответственность разработчика баз данных, если что. ;)

Andrei Ilinskii
Давай без триггеров вариант с CTE посмотрим. WITH ...

> и изоляция там по умолчанию read_commited. Значит, см. вариант 2. > Меня лишь интересовало как сделать без блокировок сделать правильные цифры. Пути, показанные тут https://t.me/pgsql/346283 и тут https://t.me/pgsql/346286 (если "..." заполнить аналогично первому примеру), на первый взгляд верные. Это если считать, что других (пишущих) транзакций, затрагивающих эту таблицу, в базе не бывает (взаимодействия с ними нужно разбирать отдельно). Собственно, это ещё одна проблема RC в нетривиальных случаях — для добавления ещё одного вида транзакции в худшем случае придётся подумать, как она будет взаимодействовать с N уже существующих. > Вот первая статья Да не читайте Вы эту чушь "статьи" (почти все те, что я в когда-либо видел, содержали грубые ошибки, например) — читайте учебники и документацию.

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
в JclConsole объявлено так: function CtrlHandler(CtrlType: DWORD): BOOL; stdcall; - где ваше объявление с stdcall? у вас на картинке нет stdcall
Karagy
8
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Карта сайта