数据库:SQL server 2005
编程语言:C#
我有一个方法可以对传递给它的User
对象进行一些处理。我希望控制此方法在具有相同用户对象的多个线程调用时的工作方式。我已经实现了一个使用数据库的简单锁定。我无法使用C#的lock
语句,因为此方法位于将在不同计算机上提供的API上。但数据库是集中的。
以下代码显示了我拥有的内容。 (为清楚起见,省略了例外处理)
例如:
void Process(User user)
{
using(var transaction = BeginTransaction())
{
if(LockUser()) {
try {
/* Other processing code */
}
finally {
UnLockUser();
}
}
}
}
LockUser()
将新条目插入数据库表。该表对用户标识有唯一约束。因此,当第二个线程尝试插入相同的数据时,约束会被违反,并且将是一个例外。 LockUser()
抓住它并返回false
。 UnlockUser
只删除锁表中的条目。
注意:请不要考虑锁定未被正确删除的可能性。我们有一个SQL作业可以清除长时间锁定的项目。
问题
考虑两个线程同时执行此方法,并且它们都启动了事务。由于事务仅在所有处理逻辑之后提交,因此在thread2上启动的事务是否会将thread1插入的数据看到锁表?
这个锁定逻辑好吗?你觉得这种方法有什么问题吗?
答案 0 :(得分:1)
如果获取锁 - 由于在数据库表中插入一个条目 - 是同一事务的一部分,那么该事务的全部或全部变化都不会对第二个线程可见。这适用于默认隔离级别(ReadCommitted)。
换句话说:无论哪个线程成功提交该单个事务,也成功获得了锁(=成功插入数据库)。
在您的代码示例中,我错过了Commit()/ Rollback()的处理。请确保将此视为实施的一部分。
答案 1 :(得分:0)
这取决于您使用的事务隔离级别。 默认隔离(ReadCommitted)级别可确保其他连接无法查看连接所做的未提交更改。
执行SQL语句时,可以使用locking hints显式获取锁定。