Как остановить те же данные в базе данных, когда сеть слишком медленная

0

Я использую следующий код, чтобы принять вызов regsiter от клиента

.post('/regsiter', async (ctx) => {
  requestfrom = JSON.parse(JSON.stringify(ctx.request.body))
  let regxemail = /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
  let email = requestfrom.email
  let password = md5(requestfrom.password)
  if (regxemail.test(email)) {
    await userModel.checkemailexist([email])
        .then(async(result) => {
            if (result.length === 0) {
                console.log("insert email to database")
                await userModel.insertUser([email,password])
            } else {
                console.log("email exist")
            }
        })
      }
})

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

  • 1
    Возможно ли, что ваши пользователи нажимают кнопку Обновить, когда получают медленные ответы? Это может составлять несколько запросов. Кроме того, ваш пример кода не показывает, где вы вставляете строку. Пожалуйста, отредактируйте свой вопрос.
  • 0
    Да, и вы не спрашивали об этом, но MD5 - это небезопасный способ хэширования ваших паролей. Восстанавливать пароли из хешей MD5 - детская игра. Если вы не уверены, почему это проблема, посетите сайт haveibeenpwned.com.
Показать ещё 3 комментария
Теги:
race-condition
koa2
database-concurrency

1 ответ

1
Лучший ответ

У вас есть состояние гонки. В частности, если ваш узел-сервер получает дублированный запрос, ожидая завершения вашего insertUser(), это второе rquest может обнаружить, что метод checkmailexist() возвращает false. Таким образом, оба параллельных процессора запросов будут пытаться вставить одно и то же значение электронной почты. Это может случиться, если ваш (нетерпеливый) пользователь нажимает Refresh или снова нажимает кнопку Submit, когда сеть работает медленно.

Другими словами, два одновременных запроса на одно и то же значение email иногда могут давать false для вашей функции checkmailexist(). Затем они оба перейдут к вызову insertUser() котором упоминается тот же email. Таким образом, вы получаете дубликат записи.

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

Системы баз данных также обеспечивают транзакции. Вы можете начать транзакцию, когда вы запрашиваете базу данных и фиксируете ее после выполнения вставки или откатываете ее, если почта уже существует. Это заставит второй вызов checkemailexist() ждать завершения первой проверки/вставки. Трудно сказать вам, как реализовать такие транзакции базы данных, не зная, что в ваших методах.

MySQL предлагает INSERT... IGNORE и INSERT... ON DUPLICATE KEY UPDATE... утверждения. Они в сочетании с уникальным ключом в столбце электронной почты позволяют обрабатывать логику дублирования в SQL.

Опять же, это обычная проблема. Все масштабируемые приложения баз данных должны иметь дело с этим.

  • 0
    Большое спасибо, это так помогает.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню