• Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    FanatPHP, Ох ты меня запутал уже XD

    Собственно как лучше построить базу для фиксирования истории транзакций и сохранения конечного баланса? так чтобы нельзя было совершить какие либо махинации с одновременными запросами?

    мой изначальный вариант скрипта в базе хранит лог транзакций, где в последней строке лога прописан актуальный баланс, сумма пополнения или списания, и для сверки старый баланс (нужен по сути только для тестов) по большей части нет разницы где будет баланс прописан, в этой же таблице или нет, в моем случае просто есть лишний столбец который можно заменить отдельной ячейкой таблицы например таблица пользователей
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    MeatPixel, в целом оно не критично, но только до тех пор, пока не придется весь лог пересчитать, дабы получить реальный баланс
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    FanatPHP, Перечитал наши комментарии и заметил что упустил твой важный ответ.
    правильно ли я понимаю, что лучше использовать такую структуру:
    таблица транзакций, по сути лог операций:
    id, user_id, datetime, operation_type, new_value, other_info
    то есть просто записываем сумму на которую нужно изменить баланс и тип операции списание или пополнение.

    А конечный баланс хранится в таблице аккаунтов например.
    Вариант:
    UPDATE account SET balance = balance - 10 WHERE user_id = 20 and balance >= 10
    то есть изначально баланс нулевой, и мы его меняем в зависимости от новых операций.
    как только мы обращаемся к таблице транзакций, то есть вносим например деньги, то следующем запросом мы вписываем в таблицу account значение balance + N и следовательно при списании balance - N

    я так понимаю простым и элегантным решением является "and balance >= 10"

    Но как быть с дубликатами лога? например мы обратились в базу с транзакцией на-10р 2 раза, с баланса списалось только 10 и условие выполнено, а в логах есть 2 записи на списание -10

    Есть какой-то похожий элегантный способ решать такую проблему?
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    FanatPHP, то есть вы предлагаете каждый раз, для отображения баланса пользователю, вытаскивать все операции с его балансом и пересчитывать конечный? "Уровень садомазо - БОГ" особенно это будет интересно считать при через 5 лет активного пользования сайтом, когда количество операций превышает 1м строк... дернуть из базы такое кол-во строк чтобы просто отобразить баланс мягко говоря бред, я понимаю что можно закешировать или закинуть в сессию и обновлять при необходимость избегая перерасчетов, но ваш вариант мягко говоря не вяжется с понятием адекватного подхода к построению базы данных.

    Я ни в коем случае не утверждаю что так делать нельзя, просто минусов в таком варианте я вижу куда больше
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    FanatPHP, Ну раз вы так умно рассуждаете, то покажите как оно должно работать, а то получается я прошу совета, а вы просто засоряете чат фразами "Михалыч, все херня, все не правильно, надо по другому!" Так дайте четкий ответ КАК правильно на ваш взгляд решать данную задачу.
  • Что я не так делаю с транзакциями PHP MYSQL?

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

    ну я к тому, что хочу понять правильное решение проблемы
    если совсем простым языком, у меня есть баланс на сайте, я условно прошу друга зайти под моим аккаунтом в магазин и по команде "ЖМИ!!" мы покупаем 2 товара за 10 рублей, при балансе 10 рублей, хотя думаю всем понятно, что 20 рублей должно было списаться, а списывается только 10 с первой транзакции, и те же самые 10 списываются в второй транзакции.

    Собственно как это реализуют крупные интернет магазины и проекты?
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    Из вашей ссылки, возьму в пример такой вот запрос, я не совсем понимаю как он работает:
    SELECT * FROM t1 WHERE c1 = (SELECT c1 FROM t2) FOR UPDATE;

    То есть по факту я делаю выборку и отмечаю, что с этой строкой я уже работаю, но я ее и не обновляю, я создаю новую на основе старой, а она в свою очередь будет доступна для чтения, или я что-то не правильно понял в логике работы "FOR UPDATE"?
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    FanatPHP, Вот именно блокировки мне и нужны. Видимо вы вообще не читали вопрос и мои ответы на ваши встречные вопросы, с чего вы взяли что у меня одна строка? вот мне просто интересно, я блин даже демо код написал, как вы в нем не увидели запрос я если честно не понимаю...если я создаю новую запись на основе предыдущей, то это уже минимум 2 строки, как у вас получается одна вообще не понимаю...
  • Что я не так делаю с транзакциями PHP MYSQL?

    @MeatPixel Автор вопроса
    Если говорить, о транзакциях, то вот выдержка из русских доков:
    это Атомарность, Согласованность, Изолированность и Долговечность (ACID). Говоря простым языком, любые действия, совершенные в рамках транзакции, гарантированно будут выполнены безопасно для базы данных, и на них не повлияют другие подключения к этой базе, даже если эти действия совершаются в несколько этапов.


    мне важен пункт "и на них не повлияют другие подключения к этой базе", собственно в данном примере это может быть хоть создание поста, хоть система лайков. речь не о бухгалтерии, вопрос лишь в том, как мне гарантированно выполнить операции в базе данных последовательно, пока выполняется запрос, другие запросы ожидают окончания первого.
  • Что я не так делаю с транзакциями PHP MYSQL?

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

    $LAST_TR = ORM::forTable('transactions')->where('user_id', UID)->orderByDesc('time')->findOne();
    $last_balance = $LAST_TR->balance; // это и есть актуальны баланс к которому нам нужно приплюсовать значение аргумента метода.


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

    Я не понимаю почему в моем случае не отрабатываю методы PDO: beginTransaction и commit
  • Как правильно перебрать такой массив?

    @MeatPixel Автор вопроса
    В целом мысль понял, попробую не сломать мозг пока буду тестировать вложенные циклы) уже пробовал но на выходе белиберда получилась, где-то точно накосячил, думал есть более элегантное решение)
  • Как подключиться по ssh к серверу и отобразить выполняющийся скрипт nodejs?

    @MeatPixel Автор вопроса
    Спасибо всем ответившим, самое подходящее решение это пакет pm2
    Краткая инструкция:
    sudo npm i pm2
    pm2 start /pach/appname.js
    pm2 monit appname