我有一个表用户,主键列电子邮件。
我有一段代码,我存储的用户只需调用userDao.store(user);
由于约束存在,我可以捕获异常并在UI上显示错误。这种方法很好。
另一种解决方案是首先检查用户是否存在,然后将其存储在数据库中。这将导致连续两次查询 - 选择,然后插入。所以基本上如果用户存在,我会显示错误。我在这里看到的问题是,如果具有相同电子邮件的两个用户尝试同时注册并提供相同的电子邮件。可能会发生两个线程检查用户的存在并且不返回任何内容。然后第一个线程保存用户,第二个线程抛出异常。
第三种方法是使用MERGE查询(我使用hsqldb)。基本上在一个查询中,只有在用户不存在时才插入用户。然后我可以看到查询的结果。如果没有行已更改,则表示用户存在,我可以显示错误。这些方法中的任何一种都不会违反我的数据的一致性。但我正在寻找如何处理这类问题的最佳实践。
答案 0 :(得分:2)
你的第一直觉是正确的。要防止重复,请在该列上定义UNIQUE
约束。然后捕获因违反该约束而导致的任何异常。
SQL缺少原子insert-if-not-exists命令。您将看到使用嵌套SELECT语句的代码,但是这样的代码不是原子的,因此您仍然需要陷入UNIQUE约束违规。
这个问题基本上是重复的。搜索StackOverflow以获取更多讨论和示例。
顺便说一句,我建议不要使用电子邮件地址作为主键。如果用户想要在其帐户上更改其电子邮件地址,则必须使用该值作为外键更新所有相关记录。我建议几乎总是使用Surrogate Key代替Natural Key。
答案 1 :(得分:-1)
发生这种情况的可能性非常小,你真的不必考虑它。特别是如果您在某人可以使用系统之前使用电子邮件验证。如果您仍然担心可以通过在检查电子邮件存在的呼叫上使用同步操作来最小化机会。唯一不起作用的方法是,如果您的集群环境中的代码在2个或更多负载平衡服务器上运行。