我理解乐观锁定和悲观锁定之间的区别。现在,谁能给我解释一下,我一般什么时候使用这两种方法?

这个问题的答案是否会随着我是否使用存储过程来执行查询而变化?

但是为了检查一下,乐观的意思是“阅读时不要锁定表”,而悲观的意思是“阅读时锁定表”。


当前回答

乐观假设你读的时候什么都不会改变。

悲观的人认为某件事会发生,所以锁定它。

如果数据被完全读取不是必要的,请使用乐观。你可能会得到奇怪的“肮脏”解读——但它不太可能导致死锁或类似的情况。

大多数web应用程序都可以接受脏读——在极少数情况下,下一次重新加载时数据不完全一致。

对于精确的数据操作(如在许多金融交易中)使用悲观。准确读取数据非常重要,没有未显示的更改——额外的锁定开销是值得的。

对了,Microsoft SQL server默认为页面锁定——基本上就是你正在读的那一行和两边的几行。行锁定更准确,但速度要慢得多。通常值得将事务设置为读提交或无锁,以避免读取时发生死锁。

其他回答

更实际的一点是,在更新分布式系统时,DB中的乐观锁定可能不足以在分布式系统的所有部分之间提供所需的一致性。

例如,在AWS上构建的应用程序中,数据通常同时存在于DB(例如DynamoDB)和存储(例如S3)中。如果一个更新同时涉及DynamoDB和S3, DynamoDB中的乐观锁定仍然可能使S3中的数据不一致。在这种情况下,使用在DynamoDB中持有的悲观锁可能更安全,直到S3更新完成。事实上,AWS为此目的提供了一个锁定库。

乐观锁定的一个用例是让应用程序使用数据库允许其中一个线程/主机“声明”任务。这是一个经常为我派上用场的技巧。

我能想到的最好的例子是使用数据库实现的任务队列,多个线程同时声明任务。如果一个任务有状态'Available', 'Claimed', 'Completed', db查询可以这样说:Set status='Claimed' where status='Available'。如果多个线程试图以这种方式改变状态,那么除了第一个线程之外,其他线程都会因为脏数据而失败。

注意,这是一个只涉及乐观锁定的用例。因此,作为“乐观锁定用于不期望有太多冲突的情况”的替代说法,它也可以用于您期望有冲突但只希望一个事务成功的情况。

我还会想到另外一种情况,悲观锁定会是更好的选择。

对于乐观锁,数据修改的每个参与者都必须同意使用这种锁。但是如果有人修改数据而不考虑版本列,这将破坏乐观锁定的整个思想。

乐观锁定意味着在读取一行时不使用排他锁,因此不会防止丢失更新或写倾斜。所以,使用乐观锁定:

如果没有发生丢失的更新或写倾斜。 或者,即使发生更新丢失或写倾斜也没有问题。

悲观锁定意味着在读取一行时使用排他锁定,从而防止丢失更新或写倾斜。所以,使用悲观锁定:

如果发生更新丢失或写倾斜。 或者出现丢失更新或写倾斜等问题。

在MySQL和PostgreSQL中,SELECT FOR UPDATE可以使用排他锁。

你可以检查我丢失更新的答案,并在MySQL中使用乐观锁定(不使用SELECT FOR update)和悲观锁定(使用SELECT FOR update)编写倾斜示例。

乐观锁定用于不期望发生太多冲突的情况。进行正常操作的成本较低,但如果碰撞确实发生,您将支付更高的代价来解决它,因为交易被中止。

悲观锁定在预期发生碰撞时使用。会违反同步的事务被简单地阻塞。

为了选择合适的锁定机制,您必须估计读取和写入的量并相应地进行计划。