Clojure 如何将唯一性验证与持久性层解耦?
假设我有一个超级简单的用户注册检查,用户的电子邮件在所有用户中必须是唯一的 我已经在这些函数中表达了这个要求Clojure 如何将唯一性验证与持久性层解耦?,clojure,coding-style,Clojure,Coding Style,假设我有一个超级简单的用户注册检查,用户的电子邮件在所有用户中必须是唯一的 我已经在这些函数中表达了这个要求 (defn validate-user [user] (and (:email user) (is-unique? (:email user)))) (defn is-unique? [email] (not (db-api/user-exists {:email email}))) 但是我想将我的验证从数据库中分离出来,我想让它完全起作用。我可能还可以将数据库API作为参数
(defn validate-user [user]
(and (:email user) (is-unique? (:email user))))
(defn is-unique? [email]
(not (db-api/user-exists {:email email})))
但是我想将我的验证从数据库中分离出来,我想让它完全起作用。我可能还可以将数据库API作为参数注入到验证用户
,如
(defn validate-user [db-api user]
(and (:email user) (is-unique? db-api (:email user))))
(defn is-unique? [db-api email]
(not ((:user-exists db-api) {:email email})))
但我不知道这是否是惯用语
而且,它感觉到
validate user
的使用者不应该关心数据库api。这种依赖性似乎破坏了将业务逻辑层与持久性层分离的整个概念。因此,我正在寻找一种心态来解释如何正确地做到这一点,或者为什么不能做到这一点。为了避免竞争条件,数据库应该处理这个约束。如果在SQL
世界中不存在INSERT
,那么您可能正在寻找它的等价物
实际上,您可以使用函数创建用户
和函数更新用户
。创建用户
功能可以使用如果不存在
检查
您无法将其与数据库分离:维护数据约束(关系世界中的关系)是数据库的责任。由于竞争条件的原因,除了数据库之外,没有人能做到这一点
让我用一个例子来说明这一点:
假设两个用户(userA和userB)希望同时创建一个帐户,但尚未选择新的电子邮件:user@example.com". 然后,系统查询数据库:
- 检查“user@example.com“不代表userA存在,它返回true
- 检查“user@example.com“不代表userB存在,它返回true
- 使用“邮件”为userA创建帐户user@example.com"
- 使用“邮件”为userB创建帐户user@example.com"
- “两个邮件帐户”user@example.com“(例如,对数据库没有约束,没有唯一索引)
- 为“userB”创建了一个帐户,但没有为userA创建帐户(例如,为userA创建帐户的请求失败,因为已经存在错误)
- 创建了一个“userB”帐户,然后“userA”的数据覆盖了“userB”中的数据(例如,update语句的语义是数据库中的user-此时可能是一个bug)
因此,您应该尝试创建一个帐户,并让数据库告诉您它是否失败。如果不自己重新创建数据库的属性(我个人不敢尝试),您就无法自己进行检查。以后是否要插入用户?如果是,那么你将有一个比赛条件与此方法。(除非你把所有的电子邮件都存储在内存中并锁定)。你是一个Ruby开发者,所以我想我应该提醒你。本节的部分内容仍适用于Clojure。