处理并发的锁定——是个好主意吗?

5
为了处理并发问题,锁定——无论是行锁、表锁还是数据库锁定都是一个好的解决方案吗? 如果不是,如何处理并发问题?
6个回答

9
如果你相信Oracle的话,那么并不会有锁问题,因为Oracle会尽力避免这种情况发生。
问题在于读者可以阻塞作家,作家必须等待所有读者完成对行的操作后才能进行写入。这会延迟写入过程及其调用程序。独占锁(用于写入)将保持到事务结束,以防需要回滚事务——这会阻止其他事务看到新值,直到事务提交为止。
实际上,如果没有太多争用,锁定通常是可以接受的,就像任何并发编程一样。如果对于一行/页/表有太多争用(很少有数据库服务器整个DB锁定),它将导致事务按顺序而不是并发执行。
Oracle使用行版本控制,即不是锁定要写入的行,而是创建该行的新版本。需要重复读取的读者记住他们读取的行的版本。但是,如果一个读取器记住了它的读取,并试图更新自此事务读取它以来已被另一个写入器更新的行,则会发生错误;这是为了防止丢失更新。为确保您可以更新一行,您必须说选择是FOR UPDATE;如果这样做,它会锁定-只有一个事务可以同时持有一行FOR UPDATE,而冲突事务必须等待。
SQL Server 2005及更高版本支持快照隔离,这是它们对行版本控制的称呼。同样,如果您需要更新刚读取的某些数据,则应请求更新锁定-在SQL Server中,使用WITH(UPDLOCK)。
锁定的另一个问题是死锁的可能性。这只是两个事务都持有对另一个需要的资源的锁定,或者一组事务持有彼此需要以进行进展的锁定。数据库服务器通常会检测到此死锁并终止其中一个事务,将其回滚-然后您需要重试操作。任何情况下,如果有多个并发事务修改相同的行,则存在死锁的可能性。如果以不同的顺序触摸行,则会发生死锁;很难强制执行数据库服务器将使用的顺序(通常希望优化器选择最快的顺序,这不一定在不同查询之间保持一致)。
通常,我建议与线程处理相同-在证明它们导致可扩展性问题之前,请使用锁定,然后找出如何使最关键的部分无锁定。

2

首先,您需要明确您的目标。在并发请求的情况下,您是希望赢得最后一个用户还是第一个用户。 数据库锁定肯定不是一种好的方式。尽可能晚地锁定表/行,并尽快释放锁。


1

可以“本地”处理并发的代码... 有什么建议吗? - Graviton
我认为他的意思是使用编程语言或库的特性,例如java.util.concurrent。 - David G
是的。还请参阅http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html。 - Rolf

1

数据库锁定 - 与表或行锁定相反 - 是处理并发的一种不好的方式;它排除了并发。


你能详细说明一下你的答案吗?这是一个不好的处理方式,因为它会阻止它发生。 - DOK
我认为他的观点是,如果你锁定了数据库,你就没有并发性,因为它被锁住了。 - Mitchel Sellers
@dok1:Mitchel说得对。如果你以独占模式锁定数据库,那么就根本没有并发访问。如果你以只读模式锁定数据库,则可以有多个人读取数据库,但没有人可以修改它。(我知道有一个DBMS可以提供对数据库的独占锁定。) - Jonathan Leffler
继续:我不知道有哪个数据库管理系统提供数据库的只读共享锁 - 但我并没有非常努力地寻找。一般来说,DBMS希望数据库随着时间的推移而发生变化。 - Jonathan Leffler

1

有许多合理的替代方式,可以避免自己编写DMBS锁定代码。需要记住的是,某种类型的锁定实际上总是会发生(原子操作等),但关键在于如果没有必要,您不希望去那里。 如果没有必要,你不想和哲学家一起用餐。交易是绕过锁定的一种方法,但这主要是针对提交而言。使用标记/指示记录已更改(Dirty bit pattern)的字段是另一种方法,只需确保以原子访问方式进行即可。通常语言中都有适当的解决方案,如之前的帖子所述,但通常语言仅支持应用程序、处理到处理级别的并发,并且有时并发必须在数据库中。我不想假设您拥有丰富的应用程序层,但如果有,有许多抽象层可以为您处理此问题。Oracle的TopLink是免费的,并且是Hibernate的更强大的兄弟,两者都可以通过抽象化、脏位、缓存和延迟锁定来帮助您管理数据库并发挑战。除非您正在为学校或个人项目编写代码,否则您真的不想自己实现这些功能。理解问题,但站在巨人的肩膀上。


0
你是指在你的应用程序中处理并发,还是解决你在数据库中遇到的并发问题。如果是前者,这不是一个好的方法。如果是后者,这可能是你不重新设计模式的唯一答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接