当网络速度如此之慢时,如何阻止相同的数据进入数据库

e3bfsja2  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(336)

我使用以下代码来接受 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 ,我怎样才能阻止这一切,有什么想法吗?

wlsrxk51

wlsrxk511#

你有比赛条件。特别是,如果您的节点服务器在等待完成任务时收到重复请求 insertUser() 方法,第二次研究可能会发现 checkmailexist() 方法返回false。因此,两个并发请求处理器将尝试插入相同的电子邮件值。当您的(不耐烦的)用户在网络速度较慢时再次单击刷新或单击提交按钮时,就会发生这种情况。
换言之,对于相同的 email 可能,有时,两者都会让你的错误 checkmailexist() 功能。然后他们会继续打电话 insertUser() 提到同样的事情 email . 所以你得到了一个重复的记录。
数据库系统提供了几种方法来处理这个非常常见的问题。一种是在表上创建一个唯一的索引,因此第二次尝试插入相同的值将引发错误。然后您的程序可以捕获并忽略双重密钥错误。
数据库系统还提供事务。您可以在查询数据库时开始事务,并在执行插入后提交它,或者在电子邮件已经存在时回滚它。这将第二次调用 checkemailexist() 等待第一次检查/插入序列完成。在不知道方法中包含什么的情况下,很难告诉您如何实现这样的数据库事务。
mysql提供 INSERT ... IGNORE 以及 INSERT ... ON DUPLICATE KEY UPDATE ... 声明。这些,再加上email列上的唯一键,让您可以处理sql中的复制逻辑。
同样,这是一个常见的问题。所有可伸缩的数据库应用程序都必须处理它。

相关问题