实体框架 - 交易范围悲观锁定

时间:2016-11-23 09:56:12

标签: c# entity-framework entity-framework-6 transactionscope pessimistic-locking

我一直在尝试使用Transaction Scope实现对EF上下文的悲观锁定。

型号:

User

Room
    ICollection<User> Users
    int Capacity

控制器:

public void List()
{
    using(var context = new MyDBContext())
    {
        // Let's pretend that this method grabs list of users from room and creates list of their names and then dumbs them
        foreach(var item in context.Rooms.First().GetUserNames()) 
            Console.WriteLine(item);
    }
}

public void Join()
{
    using(var context = new MyDBContext())
    {
        var room = context.Rooms.First();
        if(room.Users.Count >= room.Capacity)
            throw new Exception("No room");

        using(var transaction = new Transaction(
                TransactionScopeOption.Required,
                new TransactionOptions
                {
                    IsolationLevel = IsolationLevel.RepeatableRead
                }
            ))
        {
            room = context.Rooms.First(); // Fetch again to get latest version

            if(room.Users.Count >= room.Capacity)
                throw new Exception("No room");

            room.Users.Add(CurrentUser);

            context.SaveChanges();
            transaction.Complete();
        }
    }
}

现在我正在寻求批准,下面描述的行为应该有效,如果不行,我会很高兴听到反馈或建议,使其成为可能。

预期行为:

假设我们有3个线程:A - 首先调用Join(); B - 调用List(); C - 调用Join()秒。

Room.Capacity为1。

这是我期待发生的事情:A调用Join()。方法检查它是否可以加入 - 看起来像是,所以它进入TransactionScope。这时,B调用List() - 因为A还没有完成Join(),B认为房间里没有用户。这里重要的是B不会等到A完成事务,但会访问最后提交的行版本。现在,C正在调用Join()。因为A仍在处理事务,C的房间初始测试成功,所以它也进入TransactionScope。 但是由于A还没有完成,C现在应该等待它。 A完成交易,房间内的用户数现在是1.解锁交易,C进入。它再次取出Room模型,测试容量只是为了发现它无法加入,所以抛出异常。

我的事情可能会破灭:

我不确定IsolationLevel.RepeatableRead。在文档中,据说易失性数据可以在事务期间读取但不能修改。可以在交易期间添加新数据。。一方面,我希望这将允许List()方法按原样读取行,并且不会等待TransactionScope完成。此外,它应该只锁定行而不是表,因此可以添加新的房间。但我担心当A仍在运行时它不会阻止锁定C的TransactionScope。最后,我不确定“交易期间是否可以读取但未修改的易失性数据”也适用于TransactionScope。

总结一下:请告诉我,我的代码是否会按预期运行,如果没有,我应该做些什么调整才能实现?提前谢谢。

0 个答案:

没有答案