使用.NET

时间:2018-08-15 20:07:37

标签: mongodb

我需要能够获得一个独特的增量计数器。我在想这个收藏是这样的:

{
    "CounterName": "Test",
    "CounterValue": 1001
 }

我将通过获取“ Test”并增加“ CounterValue”来使用它。在RDBMS中,我将锁定行,增加CounterValue并释放。 我将如何在MongoDb中完成相同的工作?

我知道如何阅读文档并发布更新,但是我不知道如何进行锁定。

更新

如果我按如下方式使用FindOneAndUpdate,是否可以访问已找到的CounterValue?如果我能够执行x.CounterValue ++,那就太好了。

collection.FindOneAndUpdate(x => x.CounterName == "Test", Builders<InternalCounter>.Update.Set(s => s.CounterValue, XXXXXXX)

更新2

我找到了解决方案。我使用了提供的Inc. Update方法,该方法将值增加传入的值。在这种情况下,增加1。

var filter = Builders<InternalCounter>.Filter.Eq("CounterName", "Test");
var options = new FindOneAndUpdateOptions<InternalCounter> { IsUpsert = true };
InternalCounter ctn = collection.FindOneAndUpdate(filter, 
            Builders<InternalCounter>.Update.Inc(s => s.CounterValue, 1), options);

更新3

好像我很快就在说... 我认为我应该对此进行压力测试,以查看它是否确实可以锁定。我创建了一个简单的方法,该方法被5个不同的线程调用了20,000次。果然,我得到重复了。

    static void Main(string[] args)
    {       
        Console.WriteLine("Press Enter to begin...");
        Console.ReadLine();

        var t1 = Task.Run(() => TestWrites());
        var t2 = Task.Run(() => TestWrites());
        var t3 = Task.Run(() => TestWrites());
        var t4 = Task.Run(() => TestWrites());
        var t5 = Task.Run(() => TestWrites());

        Console.WriteLine("Waiting for tasks to complete...");
        Task.WaitAll(t1, t2, t3, t4, t5);
        Console.WriteLine("Done. Press Enter to exit.");
        Console.ReadLine();
    }

    private static void TestWrites()
    {
        var tester = new ConcurrentTester();
        int writes = 20000;
        for (int i = 0; i < writes; i++)
            tester.InsertCounter(tester.GetCounter());

        Console.WriteLine($"Wrote {writes}");
    }

    public int GetCounter()
    {
        var collection = database.GetCollection<InternalCounter>("Concurrency");
        var filter = Builders<InternalCounter>.Filter.Eq("CounterName", "Test");
        var mkt = collection.Find(filter).FirstOrDefault();

        var options = new FindOneAndUpdateOptions<InternalCounter> { IsUpsert = true, ReturnDocument = ReturnDocument.After };
        InternalCounter ctn = collection.FindOneAndUpdate(filter, 
            Builders<InternalCounter>.Update.Inc(s => s.CounterValue, 1), options);
        return ctn.CounterValue;
    }

0 个答案:

没有答案