Javascript-форум (https://javascript.ru/forum/)
-   Node.JS (https://javascript.ru/forum/node-js-io-js/)
-   -   Синхронная запись в БД (https://javascript.ru/forum/node-js-io-js/73612-sinkhronnaya-zapis-v-bd.html)

stweet 28.04.2018 15:48

Вот и я так думал, пока не попробовал это сделать используя базу данных. На примере обычного(локального) счетчика у меня тоже все чистенько.

EmperioAf 28.04.2018 15:51

Значит у вас проблема в логике на БД

async function registerUser(data) { // Promise<number>
    // ...
    // register_user - хранимка, возвращает integer id-а пользователя, вся логика работы с данными в ней описана
    const id = (await db.query('SELECT register_user as id FROM register_user(%)', [data])).id;
    // ...
    return id;
}

/* 
    если в БД все правильно сделано и id пользователя это primary key, 
    и например выдается какой-то последовательностью(например user_id_sequence), 
    то вы никогда не получите два одинаковых id-а вызвав функцию registerUser
*/

Aetae 28.04.2018 15:52

Цитата:

Сообщение от stweet (Сообщение 484340)
Если одновременно "два" юзера жмякнут на "поднять" оба получают "4". А в базе стоит "5" - !неудачный пример!

По логике - нет. Если изначально там 3, то один юзер получит 4 - другой 5. Какой - что - зависит от сетевых задержек. Понятия "одновременно" - не существует.
Вы можете искусственно накапливать обращения, приходящие по очереди с интервалом меньше n, и, как только дольше чем n не было обращений, красиво отправлять в базу одним куском и красиво же отправлять обратно всем, но зачем?

...upd
Цитата:

Сообщение от EmperioAf (Сообщение 484345)
Значит у вас проблема в логике на БД

Кстати да, такую мысль я даж не допускал.) В таком случае возможно что угодно.

...upd
Если уж так хочется красоты - можно сделать переменную someCount и при получении любого соответствующего ответа от базы проверять если та меньше возвращённого значения - устанавливать оное. И при ответе пользователю использовать уже её. Всё равно это не ничего не гарантирует, но будет немного "красивее".

Белый шум 28.04.2018 15:59

Цитата:

Сообщение от stweet
Что бы не получилось так, пока один юзер пытается поднять счетчик второй пытается его понизить и т.д.

Если вам нужен контроль счётчика пользователем, то логичнее периодически делать запросы к серверу и обновлять значение на странице. Иначе, разные пользователи всё-равно будут видеть разные цифры - по порядку вы им отдадите результат или нет.

EmperioAf 28.04.2018 16:00

В общем вопрос такой:
как выглядит ваша функция Model.incCounterByType?
Если это вызов к postgresql типа:
UPDATE counters SET counter = counter + 1 WHERE type = % RETURNING counter;
то все должно нормально работать

stweet 28.04.2018 16:08

Давайте на примере игры рассмотрим данную задачу. Допустим есть игра "однорукий бандит" (рулетка) и у нее есть общий баланс. Так вот, если 50 пользователей запустят эту игру (у каждого свой инстанц но общий баланс игры), выполняя какие то действия будут изменять состояние общего баланса игры. Меня пугает то, что в цикле разные ответы.
Т.е. пользователь "i" делает запрос на изменение общего баланса игры и получает "левый" ответ в тот момент когда должен был получить свой. Посмотрите внимательно на мною приведенный код в старте топика.

stweet 28.04.2018 16:10

Да, я рассматривал данное решение, но, если в момент хранения данных в памяти а не в базе рухнет сервер то он утащит за собой и память. А подняв будет масса вопросов у пользователей!

stweet 28.04.2018 16:12

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

Aetae 28.04.2018 16:16

stweet, каждый получает свой ответ.
Проблема исключительно в порядке. Но порядок в случае с пользователями не важен. Проблема решена.

EmperioAf 28.04.2018 16:19

Между этим кодом никакой разницы нет. Он делает одно и то же.
let last = Promise.resolve({})
for(let i  = 0; i < 1000; i ++) {
    last  = last .then(() => Model.incCounterByType(«one»))
        .then(res => console.log(`${i}, ${type}, ${res.counter}`))
        .catch(console.error);
}

for(let i  = 0; i < 1000; i ++) {
    try {
        const res  = await Model.incCounterByType(«one»))
        console.log(`${i}, ${type}, ${res.counter}`)
    } catch(err) {
        console.error(err);
    }
}


Часовой пояс GMT +3, время: 12:53.