Optimistic Locking是一种策略,您可以在其中读取记录,记下版本号(执行此操作的其他方法涉及日期,时间戳或校验和/哈希)并检查版本是否为't changed before you write the record back. When you write the record back you filter the update on the version to make sure it' s atomic . (即,在检查版本并将记录写入磁盘之间未进行更新)并在一次更新中更新版本 .
我能想到的最好的例子是使用数据库实现的任务队列,多个线程同时声明任务 . 如果任务的状态为“Available”,“Claimed”,“Completed”,则db查询可以说“Set status ='Claimed'where status ='Available' . 如果多个线程尝试以这种方式更改状态,除了第一个线程之外的所有线程都会因为脏数据而失败
8 回答
Optimistic Locking是一种策略,您可以在其中读取记录,记下版本号(执行此操作的其他方法涉及日期,时间戳或校验和/哈希)并检查版本是否为't changed before you write the record back. When you write the record back you filter the update on the version to make sure it' s atomic . (即,在检查版本并将记录写入磁盘之间未进行更新)并在一次更新中更新版本 .
如果记录是脏的(即与您的版本不同),则中止事务,用户可以重新启动它 .
此策略最适用于大容量系统和三层体系结构,在这些体系结构中,您不必为会话维护与数据库的连接 . 在这种情况下,客户端实际上无法维护数据库锁,因为从池中获取连接,并且您可能没有使用从一个访问到下一个访问的相同连接 .
Pessimistic Locking是您在完成记录之前锁定专用的记录 . 它具有比乐观锁定更好的完整性,但要求您小心应用程序设计以避免Deadlocks . 要使用悲观锁定,您需要直接连接到数据库(通常是two tier client server应用程序中的情况)或外部可用的事务ID,可以独立于连接使用 .
在后一种情况下,您使用TxID打开事务,然后使用该ID重新连接 . DBMS维护锁定并允许您通过TxID选择备份会话 . 这是使用两阶段提交协议(例如XA或COM+ Transactions)的分布式事务的工作方式 .
当您不期望很多碰撞时使用乐观锁定 . 执行正常操作的成本较低,但如果发生冲突,则在交易中止时,您将支付更高的价格来解决它 .
当预期发生碰撞时使用悲观锁定 . 简单地阻止违反同步的事务 .
要选择正确的锁定机制,您必须估计读取和写入的数量并相应地进行规划
乐观地假设在你阅读时没有任何改变 .
悲观假设某些东西将会锁定它 .
如果数据完全读取并不重要,请使用乐观 . 你可能会得到奇怪的“脏”读 - 但它不太可能导致死锁等 .
大多数Web应用程序都可以使用脏读 - 在极少数情况下,数据与下次重新加载不完全相符 .
对于精确的数据操作(如在许多金融交易中)使用悲观 . 准确读取数据至关重要,没有未显示的变化 - 额外的锁定开销是值得的 .
哦,并且Microsoft SQL服务器默认为页面锁定 - 基本上是您正在阅读的行以及其中的一些 . 行锁定更准确但速度更慢 . 通常值得将事务设置为read-committed或no-lock以避免在读取时出现死锁 .
除了已经说过的内容之外,应该说乐观锁定倾向于以牺牲可预测性为代价来改善并发性 . 悲观锁定往往会降低并发性,但更容易预测 .
你支付你的钱等
当悲观锁定是更好的选择时,我会想到另一种情况 .
对于乐观锁定,数据修改中的每个参与者必须同意使用这种锁定 . 但是如果有人修改数据而不关心版本列,这将破坏乐观锁定的整个想法 .
基本上有两个最受欢迎的答案 . first one基本上说
Another answer is
要么
As it is put在此页面上 .
我创建了我的答案来解释“保持连接”与“低冲突”的关系 .
要了解哪种策略最适合您,请不要考虑数据库具有的每秒事务数,而是考虑单个事务的持续时间 . 通常,您打开trasnaction,performa操作并关闭交易 . 这是一个简短的,经典的事务ANSI已经考虑到并且很好地逃脱了锁定 . 但是,您如何实施预订系统,许多客户同时预订相同的房间/座位?
您浏览优惠,填写表格,提供大量可用选项和当前价格 . 这需要花费很多时间,选项可能会过时,所有价格无效,您开始填写表格并按“我同意”按钮,因为您访问的数据没有锁定,其他人,更敏捷,有意思更改所有价格,您需要重新启动新价格 .
您可以在阅读时锁定所有选项 . 这是一种悲观的情景 . 你明白为什么它很糟糕 . 您的系统可以由一个只是开始预订并吸烟的小丑打倒 . 在他结束之前,没有人可以保留任何东西 . 您的现金流量降至零 . 这就是为什么乐观的保留在现实中使用 . 那些磨蹭太久的人不得不以更高的价格重新开始预订 .
在这种乐观的方法中,您必须记录您读取的所有数据(如mine Repeated Read)并使用您的数据版本到达提交点(我想以您在此报价中显示的价格购买股票,而不是当前价格) . 此时,将创建ANSI事务,它会锁定数据库,检查是否有任何更改并提交/中止您的操作 . IMO,这是MVCC的有效模拟,它也与Optimistic CC相关联,并假设您的事务在中止的情况下重新启动,即您将进行新的预订 . 此处的交易涉及人类用户决策 .
我还远没有理解如何手动实现MVCC,但我认为长期运行的事务与重启选项是理解主题的关键 . 如果我在任何地方都错了,请纠正我 . 我的回答是由this Alex Kuznecov chapter推动的 .
在大多数情况下,乐观锁定更有效并提供更高的性能 . 在悲观锁定和乐观锁定之间进行选择时,请考虑以下事项:
如果用户尝试同时更新数据有很多更新和相对较高的机会,则悲观锁定非常有用 . 例如,如果每个操作一次可以更新大量记录(银行可能会在每个月末向每个帐户添加利息收入),并且两个应用程序同时运行此类操作,则会发生冲突 .
悲观锁定在包含经常更新的小表的应用程序中也更合适 . 在这些所谓的热点的情况下,冲突很可能是乐观锁定浪费了回滚冲突交易的努力 .
如果冲突的可能性非常低,乐观锁定很有用 - 有许多记录,但用户相对较少,或者很少有更新,而且大多数是读取类型的操作 .
乐观锁定的一个用例是让您的应用程序使用数据库来允许您的一个线程/主机“声明”任务 . 这是一种定期为我派上用场的技巧 .
我能想到的最好的例子是使用数据库实现的任务队列,多个线程同时声明任务 . 如果任务的状态为“Available”,“Claimed”,“Completed”,则db查询可以说“Set status ='Claimed'where status ='Available' . 如果多个线程尝试以这种方式更改状态,除了第一个线程之外的所有线程都会因为脏数据而失败
请注意,这是仅涉及乐观锁定的用例 . 因此,作为“当您不期望发生许多冲突时使用乐观锁定”的替代方法,它也可以用于您期望发生冲突但只需要一个事务成功的地方 .