网络太慢时如何阻止相同的数据进入数据库
How to stop the same data into database when the network is so slow
我使用以下代码接受来自客户端
的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
是总是 ===0
,我怎样才能阻止它,有什么想法吗?
你有一个race condition。具体来说,如果您的节点服务器在等待 insertUser()
方法完成时收到重复请求,则第二个请求可能会发现 checkmailexist()
方法 returns 错误。因此,两个并发请求处理器将尝试插入相同的电子邮件值。当您的(不耐烦的)用户点击刷新或在网络速度较慢时再次点击提交按钮时,可能会发生这种情况。
换句话说,对 email
相同值的两个并发请求有时可能都会对您的 checkmailexist()
函数产生 false。然后他们将继续调用 insertUser()
并提及相同的 email
。所以你得到了一个重复的记录。
数据库系统提供了多种方法来处理这个非常常见的问题。一种是在 table 上创建一个唯一索引,因此第二次尝试插入相同的值将引发错误。然后你的程序可以捕获并忽略重复键错误。
数据库系统也提供交易。您可以在查询数据库时开始事务,并在执行插入后提交事务,或者如果电子邮件已存在则回滚事务。这将使 checkemailexist()
的第二次调用等待第一次检查/插入序列的完成。在不知道您的方法中有什么的情况下,很难告诉您如何实现此类数据库事务。
MySQL 提供 INSERT ... IGNORE
和 INSERT ... ON DUPLICATE KEY UPDATE ...
语句。这些与电子邮件列上的唯一键相结合,让您可以处理 SQL.
中的重复逻辑
同样,这是一个常见问题。所有可扩展的数据库应用程序都必须处理它。
我使用以下代码接受来自客户端
的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
是总是 ===0
,我怎样才能阻止它,有什么想法吗?
你有一个race condition。具体来说,如果您的节点服务器在等待 insertUser()
方法完成时收到重复请求,则第二个请求可能会发现 checkmailexist()
方法 returns 错误。因此,两个并发请求处理器将尝试插入相同的电子邮件值。当您的(不耐烦的)用户点击刷新或在网络速度较慢时再次点击提交按钮时,可能会发生这种情况。
换句话说,对 email
相同值的两个并发请求有时可能都会对您的 checkmailexist()
函数产生 false。然后他们将继续调用 insertUser()
并提及相同的 email
。所以你得到了一个重复的记录。
数据库系统提供了多种方法来处理这个非常常见的问题。一种是在 table 上创建一个唯一索引,因此第二次尝试插入相同的值将引发错误。然后你的程序可以捕获并忽略重复键错误。
数据库系统也提供交易。您可以在查询数据库时开始事务,并在执行插入后提交事务,或者如果电子邮件已存在则回滚事务。这将使 checkemailexist()
的第二次调用等待第一次检查/插入序列的完成。在不知道您的方法中有什么的情况下,很难告诉您如何实现此类数据库事务。
MySQL 提供 INSERT ... IGNORE
和 INSERT ... ON DUPLICATE KEY UPDATE ...
语句。这些与电子邮件列上的唯一键相结合,让您可以处理 SQL.
同样,这是一个常见问题。所有可扩展的数据库应用程序都必须处理它。