多个独立数据库事务的并发问题?
您将如何使用以下代码解决并发问题?在此示例中,我们想知道用户身份验证原因。问题是这段代码对数据库进行了两次单独的调用,但我们希望整个方法发生在概念事务内。具体来说,我们对隔离感兴趣。在确定身份验证失败的原因之前,我们不希望执行此方法期间的并发写入影响我们的读取。
我想到了一些解决方案:线程锁定、TransactionScope 和乐观锁定。我真的很喜欢乐观锁定的想法,因为我认为冲突可能很少见,但 .NET 中没有内置任何东西可以做到这一点,对吧?
另外——在这种情况下,这真的是值得关注的事情吗?什么时候需要考虑这样的并发问题,什么时候不重要?实施解决方案时需要考虑什么?表现?锁的持续时间?发生冲突的可能性有多大?
编辑:在查看了 Aristos 的答案后,我认为我真正想要的是某种“snapshot" Authenticate 方法的隔离级别。
public MembershipStatus Authenticate(string username, string password)
{
MembershipUser user = Membership.GetUser(username);
if (user == null)
{
// user did not exist as of Membership.GetUser
return MembershipStatus.InvalidUsername;
}
if (user.IsLockedOut)
{
// user was locked out as of Membership.GetUser
return MembershipStatus.AccountLockedOut;
}
if (Membership.ValidateUser(username, password))
{
// user was valid as of Membership.ValidateUser
return MembershipStatus.Valid;
}
// user was not valid as of Membership.ValidateUser BUT we don't really
// know why because we don't have ISOLATION. The user's status may have changed
// between the call to Membership.GetUser and Membership.ValidateUser.
return MembershipStatus.InvalidPassword;
}
How would you solve the concurrency issue with the following code? In this example, we'd like to know why the user failed authentication. The problem is that this code makes two separate calls to the database, but we'd like the whole method to happen inside of a conceptual transaction. Specifically we're interested in isolation. We don't want concurrent writes during the execution of this method to affect our reads before we've determined the reason for the authentication failure.
A few solutions come to mind: Thread Locking, TransactionScope and Optimistic Locking. I really like the idea of Optimistic Locking, since I think conflicts are likely to be rare, but there's nothing built into .NET to do this, right?
Also - is this something to REALLY be concerned about in this case? When are concurrency issues like this important to consider and when aren't they? What needs to be considered in implementing a solution? Performance? The duration of the lock? How likely conflicts are to occur?
Edit: After reviewing Aristos' answer, I think what I'm really after is some sort of "snapshot" isolation level for the Authenticate method.
public MembershipStatus Authenticate(string username, string password)
{
MembershipUser user = Membership.GetUser(username);
if (user == null)
{
// user did not exist as of Membership.GetUser
return MembershipStatus.InvalidUsername;
}
if (user.IsLockedOut)
{
// user was locked out as of Membership.GetUser
return MembershipStatus.AccountLockedOut;
}
if (Membership.ValidateUser(username, password))
{
// user was valid as of Membership.ValidateUser
return MembershipStatus.Valid;
}
// user was not valid as of Membership.ValidateUser BUT we don't really
// know why because we don't have ISOLATION. The user's status may have changed
// between the call to Membership.GetUser and Membership.ValidateUser.
return MembershipStatus.InvalidPassword;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据我阅读的此处和这里,它看起来像是一个
System.Transactions.TransactionScope
包装您的整个方法应该自动在公共事务中登记您的数据库调用,从而在整个事务范围内实现事务安全。你想做这样的事情:
Based on my reading here and here, it seems like a
System.Transactions.TransactionScope
wrapping your whole method should automatically enlist your database calls in a common transaction, resulting in transactional safety across the whole Transaction scope.You'd want to do something like this:
我将使用
mutex
使用名称作为锁定参数,因此只有同一用户可以锁定一段时间。对我来说,这对于一台计算机来说更安全,因为使用互斥锁,我可以捕获来自不同池或网络调用的所有可能的线程。更多评论:
Membership.ValidateUser
和Membership.GetUser
都会调用数据库。但是,如果您对进行此调用并影响此参数的页面使用标准的 asp.net 会话,那么页面已准备好锁定另一个,所以我认为没有机会需要这个互斥调用。因为会话的锁足以同步和这部分。我提醒一下,会话从头到尾都为所有用户锁定页面。
关于会话锁:
完全替换 ASP.Net 的会话
对Web服务的jQuery Ajax调用似乎是同步的
I will use
mutex
using the name as locking parametre, so only the same user may can lock out for awhile. This for me is more safe for one computer because with mutex I can capture all possible threads from different pools, or web calls.More comments: Both
Membership.ValidateUser
andMembership.GetUser
make call to the database.But if you use the standard asp.net session for the pages that make this calls and affect this parameters, then the page all ready lock the one the other so I think that there is no chance to need this mutex call. Because the lock of the session is enough to synchronize and this part. I remind that the session is locking the page from the start to the end for all users.
About session lock:
Replacing ASP.Net's session entirely
jQuery Ajax calls to web service seem to be synchronous