LINUX.ORG.RU

Как бы это назвать... коллизия? MySQL.


0

0

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

В неком проекте существуют пользователи. У этих пользователей есть общий баланс (скажем 10$). Общий баланс означает, что они оба могут пользоваться этими деньгами. С помощью этих денег на проекте можно преобретать некий товар. Суть проблемы в том, что действие приобретения товара имеет следующий вид (например пользователь №1 решил купить что-то):

1) Проверяются достаточно ли денег на общем балансе.
2) Если достаточно отсылается запрос на удаленный сервер, и ожидается подтверждение о возможности провести платеж.
3) После получения потверждения приобретается товар и снимаются деньги с пользователя.

Так, вот в момент, когда у пользователя №1 выполняется действие №2, пользователь №2 тоже начинает приобретать некий товар и для него выполняется действие №1, т.к. у первого пользователя действия три из-за долго ответа от удаленного сервера ещё не началось, деньги не снялись, то пользователь №2 успешно проходит действие №1. Но в итоге получается, что когда первый пользователь получает ответ и деньги снимаются, второго пользователя не остановить и он с таким же успехом доходит до действия №3, что может привести к появлению ОТРИЦАТЕЛЬНОГО баланса. А это крайне не допустимо.

Что можете посоветовать? Программный язык PHP, СУБД MySQL. Помогут ли в этом случае транзакции (я читал о свойствах транзакции, так называемые свойста АСИД, там все смутно, но вроде как говорят, что там не допускается выполнение двух транзакций одновременно)?

P.S. Снятие денег в действии №1 так же недопустимо, по другим соображениям.

★★★

О_О реальный генерэйшн некст. Слабо держать в запасе ещё одно поле где сумма счёта уменьшается на текущую транзакцию и сверять уже с ней?

Anoxemian ★★★★★
()
Ответ на: комментарий от Anoxemian

> держать в запасе ещё одно поле где сумма счёта уменьшается на текущую транзакцию и сверять уже с ней?

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

anonymous
()
Ответ на: комментарий от anonymous

> А потом как-то угадывать - какая часть из этой зарезервированной суммы принадлежала транзакции, сделанной из сессии

Если это платёжная система (любая) то у каждой транзакции есть идентификатор и коды ответов. Это by design. Так что ничего гадать не надо.

Anoxemian ★★★★★
()
Ответ на: комментарий от Anoxemian

> Слабо держать в запасе ещё одно поле где сумма счёта уменьшается на текущую транзакцию и сверять уже с ней?

Это все равно, что в действии №1 вычитать сумму и держать её до тех пор пока не придет подтверждение, при удачном исходе оставлять, все как есть, при неудачном возвращать обратно... есть такой вариант, но в таком случае, пока пользователь №1 проводит операцию покупки (соответсвено снимаются деньги), возможно операция по каким-то причинам обречена на неудачу, и пользователь номер №2 в этот же момент не сможеть совершить действительно нормальную покупку, так как денег на счету вроде как нет, пока пользователю №1 не придет ответ о неудаче...

Нужно, что-то более изящное.

VirRaa ★★★
() автор топика
Ответ на: комментарий от VirRaa

> Нужно, что-то более изящное.

Храни эти <b>резервации</b> как отдельные сущности ссылающиеся на аккаунт и пользователя, с атрибутами кто с какого счета зарезервировал сумму и до какого времени действительна резервация (поскольку двухфазных транзакций, видимо, удаленной системой не предусмотрено и придется как-то разруливать ситуацию когда платеж от неё пришёл с запаздыванием - но это всё равно разруливать придется, потому как если клиент через тебя что-то проплатил в удалённую систему, ответа не получил, ушел, счёт закрыл и уже и думать про это дело забыл и тут, через годы, придёт ответ от удаленной системы, что транзакция прошла успешно - то такого никому не надо).

anonymous
()
Ответ на: комментарий от VirRaa

> 1 проводит операцию покупки (соответсвено снимаются деньги), возможно операция по каким-то причинам обречена на неудачу, и пользователь.....

Именно так. Ты сейчас хочешь придумать изящный способ описать машину времени, угадывающую результат опреации наперёд? То что я предложил - позволяет отслеживать одновременно реальное движение денег и прогнозное. Надеюсь ты понимаешь что в любом случае, когда на 10$ поступят 1000 запросов о покупке, ты их разрулить без тупого отлупа не сможешь? А то что платёжная система возвращает ответы не в гарантированный срок - технически неизбежно (для тебя разумеется). Либо меняй оператора, либо требуй надлежащей работы сервиса.

Anoxemian ★★★★★
()
Ответ на: комментарий от anonymous

> с атрибутами кто с какого счета зарезервировал сумму

В том и дело, что счет один.

> Либо меняй оператора, либо требуй надлежащей работы сервиса.

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

VirRaa ★★★
() автор топика
Ответ на: комментарий от VirRaa

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

VirRaa ★★★
() автор топика
Ответ на: комментарий от VirRaa

> Здесь такая ситуация, что этот цикл может пройти меньше чем за секунду

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

насколько я понимаю именно так работает оплата банковскими картами.

INFOMAN ★★★★★
()
Ответ на: комментарий от INFOMAN

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

Цикл может пройти за секунду, а может и за 10 секунд.

В любом случае буду использовать транзакции с блокировкой конкретных полей. Другого логичного выхода судя по всему нет.

VirRaa ★★★
() автор топика
Ответ на: комментарий от anonymous

> Один на всю базу??

Смотреть топик! Один на нескольких пользователей. Общий счет называется. Даже у сотовых операторов есть.

VirRaa ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.