我理解乐观锁定和悲观锁定之间的区别。现在,谁能给我解释一下,我一般什么时候使用这两种方法?
这个问题的答案是否会随着我是否使用存储过程来执行查询而变化?
但是为了检查一下,乐观的意思是“阅读时不要锁定表”,而悲观的意思是“阅读时锁定表”。
我理解乐观锁定和悲观锁定之间的区别。现在,谁能给我解释一下,我一般什么时候使用这两种方法?
这个问题的答案是否会随着我是否使用存储过程来执行查询而变化?
但是为了检查一下,乐观的意思是“阅读时不要锁定表”,而悲观的意思是“阅读时锁定表”。
当前回答
在处理冲突时,你有两种选择:
您可以尝试避免冲突,这就是悲观锁定所做的。 或者,您可以允许冲突发生,但是您需要在提交事务时检测它,这就是乐观锁定所做的。
现在,让我们考虑以下丢失更新异常:
“丢失更新”异常可能发生在“读提交”隔离级别。
在上面的图表中,我们可以看到Alice认为她可以从她的账户中提取40,但没有意识到Bob刚刚改变了账户余额,现在这个账户中只剩下20了。
悲观锁定
悲观锁定通过对帐户使用共享或读锁定来实现这一目标,从而阻止Bob更改帐户。
在上面的图中,Alice和Bob都将获得两个用户都读过的帐户表行上的读锁。当使用可重复读取或可串行化时,数据库在SQL Server上获得这些锁。
因为Alice和Bob都读取了PK值为1的帐户,所以他们都不能更改它,直到一个用户释放读锁。这是因为写操作需要获取写/排他锁,而共享/读锁阻止了写/排他锁。
只有在Alice提交了她的事务并且在帐户行上释放了读锁之后,Bob UPDATE才会恢复并应用更改。在Alice释放读锁之前,Bob的UPDATE会阻塞。
乐观锁定
乐观锁定允许发生冲突,但在应用Alice的UPDATE时检测到它,因为版本已经更改。
这一次,我们有一个额外的版本列。每次执行UPDATE或DELETE时,版本列都会递增,它也用于UPDATE和DELETE语句的WHERE子句中。为此,我们需要发出SELECT并在执行UPDATE或DELETE之前读取当前版本,否则,我们将不知道将哪个版本值传递给WHERE子句或增加哪个版本值。
应用级事务
关系数据库系统出现于70年代末80年代初,当时客户端通常通过终端连接到主机。这就是为什么我们仍然看到数据库系统定义诸如SESSION设置之类的术语。
如今,在Internet上,我们不再在同一个数据库事务的上下文中执行读写操作,ACID也不再足够了。
例如,考虑以下用例:
如果没有乐观锁定,即使数据库事务使用Serializable,也无法捕获这个Lost Update。这是因为读写在不同的HTTP请求中执行,因此在不同的数据库事务上执行。
因此,即使在使用包含用户思考时间的应用程序级事务时,乐观锁定也可以帮助您防止丢失更新。
结论
乐观锁定是一种非常有用的技术,即使在使用不太严格的隔离级别(如Read Committed)或在后续数据库事务中执行读写时,它也能很好地工作。
乐观锁定的缺点是,在捕获OptimisticLockException时,数据访问框架将触发回滚,因此当前正在执行的事务将丢失之前所做的所有工作。
争用越多,冲突就越多,中止事务的机会就越大。回滚对于数据库系统来说代价很高,因为它需要恢复所有当前挂起的更改,这些更改可能涉及表行和索引记录。
因此,当冲突频繁发生时,悲观锁定可能更适合,因为它减少了回滚事务的机会。
其他回答
乐观假设你读的时候什么都不会改变。
悲观的人认为某件事会发生,所以锁定它。
如果数据被完全读取不是必要的,请使用乐观。你可能会得到奇怪的“肮脏”解读——但它不太可能导致死锁或类似的情况。
大多数web应用程序都可以接受脏读——在极少数情况下,下一次重新加载时数据不完全一致。
对于精确的数据操作(如在许多金融交易中)使用悲观。准确读取数据非常重要,没有未显示的更改——额外的锁定开销是值得的。
对了,Microsoft SQL server默认为页面锁定——基本上就是你正在读的那一行和两边的几行。行锁定更准确,但速度要慢得多。通常值得将事务设置为读提交或无锁,以避免读取时发生死锁。
乐观锁定用于不期望发生太多冲突的情况。进行正常操作的成本较低,但如果碰撞确实发生,您将支付更高的代价来解决它,因为交易被中止。
悲观锁定在预期发生碰撞时使用。会违反同步的事务被简单地阻塞。
为了选择合适的锁定机制,您必须估计读取和写入的量并相应地进行计划。
乐观锁定和悲观锁定是数据库中锁定数据的两种模型。
乐观锁定:仅在向数据库提交更改时才锁定记录。
悲观锁定:在编辑记录时锁定记录。
注意:在两种数据锁定模型中,锁都是在将更改提交给数据库后释放的。
关于乐观锁定和悲观锁定,上面已经说了很多好的东西。 需要考虑的一个重要问题如下:
在使用乐观锁定时,我们需要注意应用程序如何从这些故障中恢复。
特别是在异步消息驱动的体系结构中,这可能导致消息处理无序或更新丢失。
需要仔细考虑失败场景。
乐观锁定是一种策略,你读取一条记录,记下版本号(其他方法包括日期、时间戳或校验和/哈希),并在写回记录之前检查版本是否没有改变。当您写回记录时,您过滤了版本上的更新,以确保它是原子的。(即在你检查版本和将记录写入磁盘之间没有更新)和一次更新版本。
如果记录是脏的(即不同于你的版本),你中止事务,用户可以重新启动它。
这种策略最适用于大容量系统和三层体系结构,在这些体系结构中,您不必为会话维护到数据库的连接。在这种情况下,客户端实际上无法维护数据库锁,因为连接来自一个池,并且您可能不会在一次访问到下一次访问时使用相同的连接。
悲观锁定是指将记录锁定为专属使用,直到使用完毕为止。它比乐观锁具有更好的完整性,但要求您在应用程序设计时要小心,以避免死锁。要使用悲观锁定,您需要一个到数据库的直接连接(在两层客户端服务器应用程序中通常是这样),或者一个可以独立于连接使用的外部可用事务ID。
在后一种情况下,使用TxID打开事务,然后使用该ID重新连接。DBMS维护锁,并允许您通过TxID恢复会话。这就是使用两阶段提交协议(如XA或COM+事务)的分布式事务的工作方式。