validation - 一种检查行不存在并将其插入原子的常用方法?

标签 validation transactions unique atomic

我有一个网络应用程序。在其中处理表单的流程如下:

  • 验证
  • 列出错误或插入/更新数据

  • 在这个特定的场景中,我正在开发一个用户注册过程,但我试图为所有类型的表单找到一个通用的解决方案,基于检查数据库表中唯一值的可用性。

    在此用户注册中,用户的登录名必须是唯一的。在验证阶段,应用程序检查其在数据库表中的可用性,如果可用则插入一行。还有其他字段也必须验证,例如密码和密码确认。所有验证在一个 HTTP 请求中发生一次。

    问题是我不能确定 之后 应用程序检查了它的可用性,它没有被并行进程中的其他用户使用之前 第一个用户的进程插入它。我知道两个用户在同一毫秒内输入相同登录名的可能性非常小,但有一天可能会出现这种情况,即数千名用户同时向某个表单输入数据。

    如果验证已经通过,用户不应该看到一些错误消息说他的登录已经注册。

    我要解决的是确保唯一值在检查其可用性之后并将其插入 之前是可用的。一个 HTTP 请求。另一个用户注册了相同的唯一登录名,而第一个用户弄乱了他的密码并且密码确认不一样,这没关系。

    使用现有行可以轻松解决此问题,因为我可以 SELECT 它 FOR UPDATE 并且它将在事务期间被锁定。但我不能对 做同样的事情不存在排。那就是问题所在。我该如何解决这个问题?

    以下是我知道的一些解决方案。我不确定其中哪一个是最好的。另外,我不确定我知道最好的方法,所以请分享你知道的方法。

    表锁

    过去我已经用表锁定解决了这个问题,但我不确定这是不是最好的方法。过程是这样的:
  • 锁定表以进行写入
  • 检查可用性
  • 返回错误或插入行
  • 解锁表

  • 有人说锁定整个表是最糟糕的解决方案。也许是这样,但这是我自己想出的唯一可行的方法。

    锁只在一个 HTTP 请求期间保留,当然不会在几个请求之间保留。

    插入并捕获错误

    这种方式是其他一些人向我建议的。他们建议将该列设为唯一索引列,并在两个阶段分别验证和检查唯一性。过程是这样的:
  • 验证数据
  • 如果验证成功,插入行
  • 如果插入行失败显示唯一值不可用的错误

  • 当然,我已将该列设为唯一索引列。但这并不意味着我想使用数据库的能力在验证时抛出错误;它应该在应用程序级别完成。

    我不喜欢这种方式,因为我不喜欢这种情况下的 try-and-catch-an-exception 方式,因为在检查值的可用性并插入它的过程中没有任何异常。我认为它应该采用检查和保留和插入的方式。我认为验证用户输入不应该基于异常,因为用户输入错误并没有什么异常。

    我可能错了,但这是我目前的观点。如果你认为我明显错了,请告诉我为什么。

    最佳答案

    第一件事是:表锁定远非理想的解决方案。如果您预计将其扩展到数千个并发用户,锁定整个表是使您的数据库停止运行的可靠方法。您需要尽可能远离表锁定,以便拥有适当可扩展的应用程序。

    Try/catch 是我执行唯一键绑定(bind)插入的方式。在我看来,这是最好的方法。您必须意识到,任何使用行级锁定的事务数据库都是 vulnerable to deadlocks 随时 .即使在正常的、无趣的普通查询中也是如此。考虑到这一点,任何使用事务数据库的应用程序在技术上都应该具有 在 try/catch block 中执行的每个写入查询!

    当然,没有多少人会这样发展,因为在正常的日常使用中,这种情况不会经常发生。但是数据库“错误”并不总是真正意义上的错误,即您做错了什么。它们是传达数据状态的正常方式。

    最重要的是,您可以避免的锁越多,您的应用程序的可扩展性就越高。即使你可以使用 SELECT...FOR UPDATE在不存在的值上,这样做可能会显着增加该表上的死锁数量。由于使用 try/catch 很容易避免这种情况,因此我一直使用 try/catch。同样,很容易为您的数据库驱动程序创建一个通用错误处理程序包装器,以找出常见错误,例如唯一键或死锁,并适本地处理它们。

    关于validation - 一种检查行不存在并将其插入原子的常用方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2144854/

    相关文章:

    java - 单元测试中 Spring Batch JobRepository 的事务问题

    java - 如何在Spring Boot aop @Around函数中创建事务?

    PHP 从数据库中获取唯一的随机值

    validation - Haskell IO,在同一行中获取两个输入并进行验证

    javascript - 使用验证器 jQuery 在 Click 事件上验证表单

    javascript - 如何验证一组复选框并返回错误消息javascript

    mysql - 不同的查询不起作用

    ios - 在数字类型的输入中使用货币符号和逗号

    grails - 在事务 Controller Action 内部执行事务服务调用

    python - 确定数组中的重复值