mysql - 当网络很慢时如何阻止相同的数据进入数据库

标签 mysql node.js race-condition koa2 database-concurrency

我使用以下代码接受来自客户端的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 。具体来说,如果您的 Node 服务器在等待 insertUser() 方法完成时收到重复请求,则第二个请求可能会发现 checkmailexist() 方法返回 false。因此,两个并发请求处理器将尝试插入相同的电子邮件值。当您的(不耐烦的)用户在网络速度较慢时单击“刷新”或再次单击“提交”按钮时,可能会发生这种情况。

换句话说,对同一 email 值的两个并发请求有时可能都会对您的 checkmailexist() 函数产生 false 结果。然后,他们都将继续调用 insertUser(),并提及相同的电子邮件。所以你会得到一个重复的记录。

数据库系统提供了多种方法来处理这个非常常见的问题。一种是在表上创建唯一索引,因此第二次尝试插入相同的值将引发错误。然后您的程序可以捕获并忽略重复键错误。

数据库系统还提供事务。您可以在查询数据库时开始事务,并在执行插入后提交事务,或者如果电子邮件已存在则将其回滚。这将使 checkemailexist() 的第二次调用等待第一个检查/插入序列的完成。如果不知道方法中的内容,就很难告诉您如何实现此类数据库事务。

MySQL提供INSERT ... IGNOREINSERT ... ON DUPLICATE KEY UPDATE ...语句。这些与电子邮件列上的唯一键相结合,让您可以处理 SQL 中的重复逻辑。

这又是一个常见问题。所有可扩展的数据库应用程序都必须处理它。

关于mysql - 当网络很慢时如何阻止相同的数据进入数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51544744/

相关文章:

node.js - 未满足的 WebPack 对等依赖问题

Javascript/dojo - 如何防止异步调用问题?由于 dojo 小部件调用导致的 RACE 条件

Java HashMap 竞争条件

mysql - 错误代码 : 1054. 's.Product_id' 中的未知列 'on clause' 错误代码 : 1054. 's.Product_id' 中的未知列 'on clause'

sql - MySQL,如果列等于,则选择行?否则选择使用默认值

mysql - MySQL 中的列排序

mysql - 无法 POST/api/dogs

java - 从数据库填充组合框

javascript - 使用 Node 中的 Q promise 库在值数组上顺序调用/执行相同的函数;并返回一个包含结果的新数组/集合

c++ - 并行写入相同的值