假设我有一个简单的对象:
class A
{
int _id;
int V1;
int V2;
}
和一堆MongoDB表:
现在,我有两个异步更新操作定义如下:
void UpdateV1(int id, int V)
{
var F = Builders<A>.Filter.Eq(_ => _._id, Id);
var U = Builders<A>.Update.Set(_ => _.V1, V);
Mongo.Driver.UpdateOneAsync(F, U);
}
void UpdateV2(int id, int V)
{
var F = Builders<A>.Filter.Eq(_ => _._id, Id);
var U = Builders<A>.Update.Set(_ => _.V2, V);
Mongo.Driver.UpdateOneAsync(F, U);
}
如果我运行以下命令:
UpdateV1(1, 10);
和
UpdateV2(1, 20);
在不同的线程上,但大致在同一时间,发生了什么?
我能得到:
我之所以这样问是因为我们有一个非常奇怪的错误,看起来第一个选项就是发生了什么,但预期结果显然是最后一个。
当我们进行阻止呼叫时,这些问题开始消失,但也可能是副作用。
这是使用C#驱动程序,所有最新版本。
答案 0 :(得分:0)
我认为这不是您的查询问题,因为mongodb保证原子性和并发控制可以查看此link以获取更多信息。
你的问题来自我怀疑的任务安排方式。
看看这个例子,如果你没有等待Parallel.Invoke
中的结果,你的查询将不会被执行,因为进程将在执行任务之前退出。因此,如果添加Console.ReadLine()
,您的流程将被阻止,从而允许mongo运行任务
namespace ConsoleApplication1
{
class Program
{
static MongoClient mongoClient = new MongoClient();
static IMongoDatabase databaseBase = mongoClient.GetDatabase("dbTest", null);
static IMongoCollection<A> collection = databaseBase.GetCollection<A>("tests", null);
static void Main(string[] args)
{
var a = new A
{
_id = 1,
V1 = 0,
V2 = 0
};
Parallel.Invoke( ()=> { var res=UpdateV1(1, 10).Result; }, ()=> { var res = UpdateV2(1, 20).Result; });
//Console.ReadLine();
}
static async Task<long> UpdateV1(int id, int V)
{
var F = Builders<A>.Filter.Eq(a => a._id, id);
var U = Builders<A>.Update.Set(a => a.V1, V);
var result = await collection.UpdateOneAsync(F, U);
return result.ModifiedCount;
}
static async Task<long> UpdateV2(int id, int V)
{
var F = Builders<A>.Filter.Eq(_ => _._id, id);
var U = Builders<A>.Update.Set(_ => _.V2, V);
var result = await collection.UpdateOneAsync(F, U);
return result.ModifiedCount;
}
}
class A
{
public int _id;
public int V1;
public int V2;
}
}
您可能只需将UpdateOneAsync
替换为UpdateOne
,看看会发生什么?