C# MongoDB从多个进程并发写入/获取导致批量写入操作错误
我目前正在实现一个用于缓存的MongoDB数据库 我制作了一个非常通用的客户端,save方法的工作原理如下:C# MongoDB从多个进程并发写入/获取导致批量写入操作错误,c#,asp.net,mongodb,concurrency,web-garden,C#,Asp.net,Mongodb,Concurrency,Web Garden,我目前正在实现一个用于缓存的MongoDB数据库 我制作了一个非常通用的客户端,save方法的工作原理如下: public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data) { if (data == null || !data.Any()) return; var collection = Connector.MongoDatabas
public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data)
{
if (data == null || !data.Any())
return;
var collection = Connector.MongoDatabase.GetCollection<T>(collectionKey.ToString());
var filter = new FilterDefinitionBuilder<T>().Empty;
var operations = new List<WriteModel<T>>
{
new DeleteManyModel<T>(filter),
};
operations.AddRange(data.Select(t => new InsertOneModel<T>(t)));
try
{
collection.BulkWrite(operations, new BulkWriteOptions { IsOrdered = true});
}
catch (MongoBulkWriteException mongoBulkWriteException)
{
throw mongoBulkWriteException;
}
}
使用此索引:
string TranslationSettings()
{
var indexBuilder = new IndexKeysDefinitionBuilder<TranslationSetting>()
.Ascending(_ => _.SettingKey)
.Ascending(_ => _.LanguageCode);
return MongoDBClient.CreateIndex(DefaultCollectionKeys.TranslationSettings, indexBuilder);
}
string TranslationSettings()
{
var indexBuilder=new IndexKeysDefinitionBuilder()
.Ascending(=>.SettingKey)
.Ascending(=>.LanguageCode);
返回MongoDBClient.CreateIndex(DefaultCollectionKeys.TranslationSettings,indexBuilder);
}
您为什么不使用“upsert”更新One?当然,我们无法看到您的所有体系结构,但多个“工作人员”可能发布相同的数据(名称和电子邮件的组合)。所以“提升者”就是为了克服这个问题。事实上,甚至还有ReplaceOne
,它基本上只是一个没有原子操作符的更新,比如$set
,如果您的意图是总是覆盖的话。是的,我的意图是总是覆盖。考虑到我如何接受该方法,我无法设置字段。UpdateOne要求为更新设置字段。也许这可以通过反射来解决,但它似乎过于复杂。然后使用ReplaceOne
。这不是一个建议,而是如何做的。底线是2个或多个进程要求数据库“覆盖”一个可能的现有条目或创建一个新条目,这不是问题,因为最坏的情况是发生的写入比实际需要的要多。但是两个或更多的进程同时发出Delete和insert只是自找麻烦。因此,ReplaceOne
就是解决数据库端问题的方法。从长远来看,您可能应该了解这些任务是如何分配出去的,以及为什么多个流程处理相同的数据。但首先要消除不良影响。目前正在尝试此解决方案。只有最后一个元素实际被持久化时出现问题。我的猜测是,当前设置为空的筛选器将告诉ReplaceModel替换与筛选器匹配的所有内容。你有解决这个问题的经验吗?如果你有问题,你可以展示你正在尝试的代码。但通常情况下,应用任何“upsert”操作的“filter”是“unique key”。在您的情况下,Name
和Email
字段在抛出重复键错误时具有唯一索引。您为什么不使用“upsert”来UpdateOne
?当然,我们无法看到您的所有体系结构,但多个“工作人员”可能发布相同的数据(名称和电子邮件的组合)。所以“提升者”就是为了克服这个问题。事实上,甚至还有ReplaceOne
,它基本上只是一个没有原子操作符的更新,比如$set
,如果您的意图是总是覆盖的话。是的,我的意图是总是覆盖。考虑到我如何接受该方法,我无法设置字段。UpdateOne要求为更新设置字段。也许这可以通过反射来解决,但它似乎过于复杂。然后使用ReplaceOne
。这不是一个建议,而是如何做的。底线是2个或多个进程要求数据库“覆盖”一个可能的现有条目或创建一个新条目,这不是问题,因为最坏的情况是发生的写入比实际需要的要多。但是两个或更多的进程同时发出Delete和insert只是自找麻烦。因此,ReplaceOne
就是解决数据库端问题的方法。从长远来看,您可能应该了解这些任务是如何分配出去的,以及为什么多个流程处理相同的数据。但首先要消除不良影响。目前正在尝试此解决方案。只有最后一个元素实际被持久化时出现问题。我的猜测是,当前设置为空的筛选器将告诉ReplaceModel替换与筛选器匹配的所有内容。你有解决这个问题的经验吗?如果你有问题,你可以展示你正在尝试的代码。但通常情况下,应用任何“upsert”操作的“filter”是“unique key”。在您的情况下,Name
和Email
字段在抛出重复键错误时具有唯一索引。
public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data)
{
if (data == null || !data.Any())
return;
var collection = Connector.MongoDatabase.GetCollection<T>(collectionKey.ToString());
var filter = new FilterDefinitionBuilder<T>().Empty;
var operations = new List<WriteModel<T>>();
operations.AddRange(data.Select(t => new ReplaceOneModel<T>(filter, t) { IsUpsert = true }));
try
{
collection.BulkWrite(operations, new BulkWriteOptions { IsOrdered = true });
}
catch (MongoBulkWriteException mongoBulkWriteException)
{
throw mongoBulkWriteException;
}
}
public class TranslationSetting
{
[BsonId(IdGenerator = typeof(GuidGenerator))]
public object ObjectId { get; set; }
public string LanguageCode { get; set; }
public string SettingKey { get; set; }
public string Text { get; set; }
}
string TranslationSettings()
{
var indexBuilder = new IndexKeysDefinitionBuilder<TranslationSetting>()
.Ascending(_ => _.SettingKey)
.Ascending(_ => _.LanguageCode);
return MongoDBClient.CreateIndex(DefaultCollectionKeys.TranslationSettings, indexBuilder);
}