举一个简单的例子:
我有一个只有一个表的数据库:名称,其中有100万条记录,每个记录包含一个普通的男孩或女孩的名字,并且每天都有更多记录。
我有一个应用程序服务器,使用我的网站“名称选择器”将父母的http请求作为输入。对于每个请求,我需要从数据库中选择一个名称并返回它,然后不将该名称提供给另一个父对象。服务器是并发的,因此可以处理大量请求,但必须遵守“每个请求的唯一名称”,并且仍然具有很高的可用性。
此用例的体系结构的主要组成部分和策略是什么?
答案 0 :(得分:1)
据我了解,您有两项操作:添加名称和选择名称。
我有几个问题:
问题1:父母只选择了名字还是他们也添加了名字?
问题2 如果它们添加名称,这并不意味着当添加名称时,它也应标记为< em>已经选择?
假设您不想让所有名称选择请求都彼此等待(通过锁定它们):
仅在使用选择名称的情况下解决并发的一种解决方案是使用Optimistic offline lock。
最常见的实现方法是在表中添加一个version字段,并在您将名称标记为 choose 时将该版本递增。您将需要数据库支持,但是大多数数据库都为此提供了一种机制。默认情况下,MongoDB将版本字段添加到文档中。对于RDBMS(例如SQL),您必须自己添加此字段。
您尚未指定要使用的技术,因此我将举一个使用伪代码编写SQL DB的示例。对于MongoDB,您可以检查数据库如何为您进行这些检查。
NameRecord {
id,
name,
parentID,
version,
isChosen,
function chooseForParent(parentID) {
if(this.isChosen){
throw Error/Exception;
}
this.parentID = parentID
this.isChosen = true;
this.version++;
}
}
NameRecordRepository {
function getByName(name) { ... }
function save(record) {
var oldVersion = record.version - 1;
var query = "UPDATE records SET .....
WHERE id = {record.id} AND version = {oldVersion}";
var rowsCount = db.execute(query);
if(rowsCount == 0) {
throw ConcurrencyViolation
}
}
}
// somewhere else in an object or module or whatever...
function chooseName(parentID, name) {
var record = NameRecordRepository.getByName(name);
record.chooseForParent(parentID);
NameRecordRepository.save(record);
}
在将对象保存到数据库之前,必须执行版本比较。 SQL提供了一种根据某些条件执行查询并返回受影响的行的行数的方法。在本例中,我们检查数据库中的版本是否与更新前的旧版本相同。如果不是,则表示其他人已更新记录。
在这种简单情况下,您甚至可以删除版本字段,并在SQL查询中使用isChosen标志,如下所示:
var query = "UPDATE records SET .....
WHERE id = {record.id} AND isChosend = false";
向数据库添加新名称时,将需要一个唯一常量来解决并发问题。