Задать вопрос
  • Как защититься от двойного списания в многопоточном приложении?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Трата состоит из трех этапов. Чтение баланса пользователя, проверка хватает ли средств и собственно запись нового баланса.

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

    баланс юзера расчитывается на лету и не хранится в юзере. Расчитывсется на основе истории его пополнений/расходов.

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

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

    Как раз уровень изоляции. При правильно выбранном уровне хрен чего второй прочитает, пока первый не завершит свою транзакцию и не отпустит ресурсы.
    Ответ написан
    1 комментарий
  • Как защититься от двойного списания в многопоточном приложении?

    @rPman
    Блокировку во время траты уже сказали, но бывает что процесс может длиться достаточно долго, чтобы пользователь в соседнем окошке не смог совершить параллельно оплату (у него будет все висеть), поэтому блокировки реализуют программно

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

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

    если проверка прошла, то обе выполнятся

    Кто сказал что СУБД позволит выполнить обе транзакции с одними и теми же исходными данными?
    Если обе транзакции начали исполняться параллельно, прочитали одни и те же данные, и пытаются их перезаписать, как СУБД будет себя вести? Позволит ли она вообще отработать обеим транзакциям? Или одна их них подождёт, пока не закончит работу другая? Вопрос гораздо интереснее, чем кажется. И, что самое главное, неглупые люди уже подумали над ним. Очень хорошо подумали.

    В доках постгреса написано ещё лучше.

    Или лучше каждый раз пересчитыапть из истории?

    Запаритесь пересчитывать, это не масштабируется, сложность расчёта будет всё время расти. Если считаете, что можете накосячить с текущим балансом - сделайте возможность его пересчёта согласно истории пополнений/трат. Это называется денормализованными данными. Это один из тех случаев, когда оправдано применение хранимых процедур для актуализации таких данных. Т.е. вместо непосредственной записи одновременно и в историю пополнений/трат и в актуальный баланс прямо из приложения, вы вместо этого вызываете хранимую процедуру, которая атомарно как пишет новую операцию - это ваши основные данные - так и меняет нужным образом ваши денормализованные данные - т.е. ваш баланс. Заодно в этой же хранимке можно дополнительно проверить возможность списания. Это решение не очень хорошо масштабируется, и вообще хранимки это антипаттерн для современных модных-молодёжных распределённых приложений, но судя по вашим вопросам врядли вы отвечаете за разработку сервиса, где таких списаний десятки тысяч в секунду, так что вам хватит.

    Вот на SO ещё предлагают много решений этой классической проблемы, ни одно из которых не является идеальным и лучшим для всех ситуаций.
    Ответ написан
    Комментировать
  • Решение задачи совсем не пойму ее?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Неужели так сложно проверить, что каждый
    следующий элемент не
    меньше предыдущего


    А с массивом-то сделать можете?
    Ответ написан
    Комментировать
  • Фриланс: какие специальности не оккупировали "индусы"?

    @Stalinko Куратор тега Фриланс
    PHP'шник и фрилансер до мозга костей
    С таким уровнем я бы рекомендовал набраться опыта в офисе или где-то в работе по найму.
    Лезть во фриланс с нуля - это крест на своей карьере.

    Нормальные опытные люди вообще не конкурируют с индусами.
    Ответ написан
    Комментировать
  • Почему скрипты знают друг о друге?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Если вы эти файлы подключаете на одной странице, то глобальная область видимости у них одна на всех. Соответственно и переменные, размещаемые в глобальной области, будут общими.
    Ответ написан
    Комментировать
  • Как исправить ошибку " Command errored out with exit status 1:"?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    Похоже на то, что для сборки библиотеки нужен компилятор C, а у вас в системе он не установлен или не настроен.
    Ответ написан
    1 комментарий
  • Яндекс.Практикум C++ Что я делаю не так?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вся проверка должна быть query[i] == ' '

    to_string(32) - вернет вам "32" вместо пробела. Тогда уж можно делать (char)32 или static_cast<char>(32). Но ' ' - все равно лучше.

    И еще вы не выводите длину всей строки в конце - ведь там всегда заканчивается слово (может быть пустое).
    Ответ написан
  • Если входящий TCP порт 12345 занят, то исходящий TCP порт 12345 будет закрыт?

    CityCat4
    @CityCat4 Куратор тега Сетевое администрирование
    Жил да был черный кот за углом...
    Не бывает портов входящих и исходящих. Он бывает просто порт и он либо занят либо нет. Если он занят, то занят ;)
    Ответ написан
    Комментировать
  • Жёсткий диск мешает работает компьютера?

    @Voland69
    Мешать может, винда иногда грешит блокирующим IO даже не на системном диске. А бэды и IO ошибки резко увеличивают latency, что визуально ощущается как тормоза.
    Для начала посмотреть SMART диска. Если бэды, то менять диск, если ошибки IO, то для начала можно кабель поменять.

    P.S. ЕМНИП это далеко не первый вопрос от Вас на эту тему, везде в ответах говорилось про проверку SMART но от Вас я реакции не видел. Скачайте прогу по ссылке и приложите скрин.
    Без диагностики харда все остальное - гадание на кофейной гуще.
    Ответ написан
    1 комментарий
  • Как безопасно открыть вирус с почты?

    Adler_lug
    @Adler_lug
    В блокноте откройте или любом другом текстовом редакторе.
    Ответ написан
    7 комментариев
  • Рекурсия, зачем она нужна, и используете ли вы её?

    а зачем нужна рекурсия, если всегда можно обойтись без неё?

    Некоторые алгоритмы очень хорошо выглядят, если реализуются через рекурсию (но не всегда эффективно).
    Те же алгоритмы, которые строятся на стратегии "разделяй и властвуй", когда у тебя есть большой набор данных, и ты можешь его разделить на наборы по меньше, которые обрабатывать независимо.
    Например вот псевдокод для конвертации json-DOM в объекты:
    fun ConvertJsonElementToObject(element: JsonElement): Object {
      return match(element.type) {
        Number(num) -> num as Object,
        String(str) -> str as Object,
        Array(elements) -> elements.map(ConvertJsonElementToObject) as Object,
        Object(dict) -> dict.mapValues(ConvertJsonElementToObject) as Object,
        Null -> null as Object
      }
    }
    Ответ написан
    Комментировать
  • Как в безопасном режиме Windows с поддержкой командной строки провернуть экран?

    borisdenis
    @borisdenis
    Ленив и вреден...
    Безопасный режим на то и безопасный, что в нём загружается минимально возможный набор только стандартных драйверов обеспечивающих работу ОС с целью восстановления. Драйвер видеокарты загружается только базовый, без всяких свистоперделок, он не умеет поворачивать экран. Так что никак.
    Ответ написан
    2 комментария
  • Лучший ssh клиент с подсказкой и сохранением команд?

    @rPman
    в корне неверный подход использования инструментов:
    * чтобы не вводить пароли, нужно настраивать беспарольную аутентификацию по ключу
    * для длинных доменов можно настроить алиасы по их адресу в /etc/hosts либо создать локально скрипты или алиасы bash на всю команду подключения (к примеру если часто нужно еще и нестандартный порт указывать)
    * автодополнение команд выполняется не на твоей машине, а на удаленной, штатным инструментом bash completion, так же можно использовать другие шелы типа zsh, 'все в голос' считают его удобнее, но нужно привыкать и настраивать.

    про автодополнение по истории команд, смотри этот вариант
    Ответ написан
    2 комментария
  • Почему я не могу получить доступ к элементу unordered_map обходом?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    unordered_map<string, button>::const_iterator it_button;
    ...
    it_button->second.hoverReact(m, w); //проблема

    Почему second это CONST button? Почему не просто button?

    Потому что const_iterator же.
    Ответ написан
    Комментировать
  • Есть разница, на низком уровне, между классом со статичными полями и глобальным экземпляром класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Нет разницы.

    Можно же проверить самостоятельно. Технологии нынче - все легко. Вот: https://godbolt.org/z/PKWPdY4nn

    Как видите, и то и другое компилируется в практически одинаковые инструкции:

    eax, DWORD PTR MyGlobalPool[rip+4]
    ...
    eax, DWORD PTR MyPool1::numOfAllocatedObjects[rip]


    И там и там просто загрузка какого-то статичного адреса глобальной переменной. Вообще говоря, в случае с глобальной переменной компилятор мог бы сдлеать и 2 действия: взять адрес переменной и прибавить смещение поля. Но он, как видите, достаточно умный, чтобы сделать все в одну инструкцию.
    Ответ написан
    Комментировать
  • Почему в WinAPI вместо русского языка выводятся иероглифы?

    @User700
    MessageBox может подключиться как MessageBoxA, требующую однобайтную кодировку; или как MessageBoxW для юникода. Префикс L объявляет юникодную строку. При компиляции нет предупреждений о приведении типов? Возможно настроено на использование MessageBoxA. можете указать явно MessageBoxW. Хотя нет, при такой ошибке не компилировалось бы.
    Может быть дело в том, в какой кодировке компилятор понимает файл исходного кода:
    https://qna.habr.com/q/525512
    Ответ написан
    Комментировать
  • Выводятся какие-то цифры и ошибка, что не так?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    При j == 7 куда обращается arr[j + 1] ?
    Ответ написан
    Комментировать