无需,就无需依赖数据库,就可以确保一个字段(例如,用户的emailAddress
)是唯一的。
一些常见的失败尝试:
emailAddress
是否存在(通过查询数据库),如果不存在,则创建用户。现在,很明显,在“先检查后执行”窗口中,其他线程可以创建具有相同电子邮件的用户。因此,这种解决方案不好。数据库是每个线程和每个服务实例将写入的单一数据源,因此在此处实现unique constraint
很有意义。但这对于关系数据库仍然适用。
那 NoSql 数据库呢?有些确实允许一个唯一的约束,但这不是他们的本机行为,或者也许是。
但是不使用数据库实现字段唯一性的问题是,可能有什么选择?
答案 0 :(得分:0)
我认为您的问题更为笼统-“如何确保数据库写入操作成功完成,以及如何处理未成功的情况?”。唯一性只是一种失败模式-您可能试图插入一个太大的值,错误的数据类型或与外键约束不匹配的值。
关系数据库通过符合ACID的要求来解决此问题,并在事务失败时引发错误以供客户端处理。
您需要ACID的(部分)好处,而无需关系数据库。那是相当大的topic对话。解决此问题的明显方法是在应用程序层中引入“事务”的概念。例如,在您的情况下,您可能会发送“创建帐户(emailAddress,名称,...)”消息,并让应用程序侦听“ accountCreated”或“ accountCreationFailed”响应。该消息的接收者负责写入数据库;您有两种选择。一种是锁定该线程(因此任何时候任何一个进程都只能写入数据库)。那不是超级可扩展的。我使用的另一种机制是引入状态标志-您使用“草稿”标志将帐户数据写入数据库,然后检查您的约束条件(包括唯一性),如果将“草稿”标志设置为“已验证”满足约束条件(即没有其他记录具有相同的电子邮件地址),如果没有,则“失败”。
答案 1 :(得分:0)
要检查唯一性,您需要存储程序的“状态”。为了安全起见,您需要能够以事务方式将更改应用于状态。
选择哪个状态存储,它应该支持事务。有几种方法可以实现事务并实现一致性。许多类似PostgresSQL的关系数据库都是通过实现MVCC算法来实现的。在分布式环境中,您必须查找诸如2PC,Paxos等的分布式事务。
通常每个人都依赖可用的数据存储解决方案,除非对该项目有奇怪或特定的要求。
最后,沟通模式与这里的潜在问题无关。例如,在您提到的Actor案例中,一天结束时,每个actor都必须查询状态以查找是否存在电子邮件。如果您的状态存储支持Serializability,则不会有问题,也不会发生冲突(将错误传达给客户端是另一个问题)。假设您正在使用PostgreSQL。发出插入/更新查询时,它将包裹在事务中,并且底层MVCC算法将处理所有事务。在高级且分散的环境中,您可以使用支持分布式事务的数据存储,例如CockroachDB。如果您想深入研究,可以研究以下关键字:ACID,隔离级别,原子性,可序列化性,CAP定理,2PC,MVCC,分布式transaciton,分布式锁,...