Я использую следующий код, чтобы принять вызов 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
, как могу ли я остановить это, любые идеи?
У вас есть состояние гонки. В частности, если ваш узел-сервер получает дублированный запрос, ожидая завершения вашего insertUser()
, это второе rquest может обнаружить, что метод checkmailexist()
возвращает false. Таким образом, оба параллельных процессора запросов будут пытаться вставить одно и то же значение электронной почты. Это может случиться, если ваш (нетерпеливый) пользователь нажимает Refresh или снова нажимает кнопку Submit, когда сеть работает медленно.
Другими словами, два одновременных запроса на одно и то же значение email
иногда могут давать false для вашей функции checkmailexist()
. Затем они оба перейдут к вызову insertUser()
котором упоминается тот же email
. Таким образом, вы получаете дубликат записи.
Системы баз данных предоставляют серверные способы решения этой очень распространенной проблемы. Один из них - создать уникальный индекс в вашей таблице, поэтому вторая попытка вставить одно и то же значение вызовет ошибку. Тогда ваша программа может поймать и проигнорировать повторяющуюся ошибку ключа.
Системы баз данных также обеспечивают транзакции. Вы можете начать транзакцию, когда вы запрашиваете базу данных и фиксируете ее после выполнения вставки или откатываете ее, если почта уже существует. Это заставит второй вызов checkemailexist()
ждать завершения первой проверки/вставки. Трудно сказать вам, как реализовать такие транзакции базы данных, не зная, что в ваших методах.
MySQL предлагает INSERT... IGNORE
и INSERT... ON DUPLICATE KEY UPDATE...
утверждения. Они в сочетании с уникальным ключом в столбце электронной почты позволяют обрабатывать логику дублирования в SQL.
Опять же, это обычная проблема. Все масштабируемые приложения баз данных должны иметь дело с этим.