隔离级别与乐观锁定休眠

Dhr*_*ruv 4 database orm hibernate jpa

我有一个Web应用程序,要确保与我尝试更新的对象上的数据库级别锁并发。我想确保批量更改或其他用户或进程可能不会最终导致数据库中的不一致。

我看到隔离级别可确保读取一致性,并且对@Version字段的乐观锁定可以确保数据以一致的状态写入。

我的问题是我们不能仅确保与隔离级别的一致性吗?通过进行任何更新记录Serializable的事务(不考虑性能),我是否不能确保该事务已采取了适当的锁定,而其他任何试图更新或获取锁定的事务都将失败?为此,我真的需要版本或时间戳管理吗?

Pio*_*aza 6

根据您选择的隔离级别,特定资源将被锁定,直到给定事务提交或回滚为止-它可以锁定在整个表,行或sql块上。这是一种悲观的锁定,并且在运行事务时可以在数据库级别上确保。

另一方面,乐观锁定假定多个事务很少相互干扰,因此在此方法中不需要锁定。这是应用程序侧检查,使用@Version属性来确定记录的版本在获取和尝试更新之间是否已更改。

在Web应用程序中使用乐观锁定方法是合理的,因为大多数操作都跨越多个HTTP请求。通常,您在一个请求中从数据库中获取一些信息,然后在另一个请求中对其进行更新。长时间保持数据库资源锁定来保持事务打开是非常昂贵且不明智的。这就是为什么我们假设没有人会使用我们正在处理的数据集的原因-它更便宜。如果假设碰巧是错误的,并且其他人在两次请求之间更改了版本,则Hibernate将不会更新该行,而是会抛出OptimisticLockingException。作为开发人员,您有责任管理这种情况。

简单的例子。在线拍卖服务-您正在观看商品页面。您阅读了其说明和规范。假设所有过程都需要5分钟。通过悲观的锁定和某些隔离级别,您可以阻止其他用户访问此特定项目页面(甚至所有项目!)。通过乐观锁定,每个人都可以访问它。在阅读了有关该项目的内容后,您愿意出价,因此您单击适当的按钮。如果与此同时有其他用户观看此项目并更改其状态(所有者更改了其描述,其他人对其进行了出价),则您可能会(取决于应用程序的实施情况)被告知有关更改,然后应用程序才会接受您的出价,因为版本已经与数据库中保留的版本不同。

希望能为您澄清一些事情。

  • 我不确定你在说什么数据库,但根据[postgres中可序列化的描述](https://www.postgresql.org/docs/9.5/static/transaction-iso.html#XACT-SERIALIZABLE)它实际上表现得更像乐观锁——引发错误而不是锁定。锁定必须通过 SELECT FOR UPDATE 来完成。 (2认同)

Mac*_*ski 3

除非我们正在谈论一些小型的、独立的 Web 应用程序(仅在数据库上运行的应用程序),否则使所有事务都可序列化意味着对您的设计有很大的信心,而不是考虑到它的事实可能不是唯一访问该特定数据库的应用程序。

在我看来,结合可序列化隔离级别,或者换句话说,悲观锁,应该很好地通过决策和应用:

  • 大型数据库和仅更新几行的短事务
  • 两个并发事务修改相同行的机会相对较低。
  • 相对长时间运行的事务主要是只读的。

根据我的经验,在大多数情况下,仅使用乐观锁将是最有益的决定,因为频繁的并发修改通常只发生在一小部分情况下。乐观锁定肯定还可以帮助其他应用程序运行得更快(不要只考虑自己!)。

因此,当我们采用悲观-乐观锁定策略系列时,我认为事实更接近于带有可串行化风格的乐观锁定。

我真的无法在这里引用任何内容,因为答案是基于我在许多复杂的 Web 项目中的个人经验以及我准备 JPA 证书时的笔记。

希望有帮助。