问题标签 [optimistic-locking]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
4 回答
671 浏览

ruby-on-rails - 如果两个人同时提交编辑会发生什么

这可能是一个愚蠢的问题,但我想知道如果两个用户同时编辑一些数据然后同时点击提交会发生什么,我假设 Rails 一个接一个地处理请求,所以有人会收到一条错误消息,但是这对吗?

谢谢

一旦一个人编辑了数据,我不希望它再被访问或编辑,这是由验证处理的

我在我的模型中也得到了这个验证

如果验证通过,则 active 是控制器内的布尔集

0 投票
2 回答
8231 浏览

ruby-on-rails - 如何在我的 Rails 应用程序中避免竞争条件?

我有一个非常简单的 Rails 应用程序,它允许用户注册他们参加一组课程的情况。ActiveRecord 模型如下:

ScheduledRun 实例的可用名额有限,一旦达到限制,就不能再接受出席。

出勤计数是一个计数器缓存列,保存为特定 ScheduledRun 记录创建的出勤关联的数量。

我的问题是我不完全知道正确的方法来确保当一个或多个人同时尝试注册课程的最后一个可用位置时不会发生竞争情况。

我的考勤控制器如下所示:

如您所见,它没有考虑 ScheduledRun 实例已经达到容量的位置。

对此的任何帮助将不胜感激。

更新

我不确定这是否是在这种情况下执行乐观锁定的正确方法,但这是我所做的:

我在 ScheduledRuns 表中添加了两列 -

我还向 ScheduledRun 模型添加了一个方法:

保存出勤模型后,ActiveRecord 继续更新 ScheduledRun 模型上的计数器缓存列。这是显示发生这种情况的日志输出 -

如果在保存新的出勤模型之前对 ScheduledRun 模型进行了后续更新,这应该会触发 StaleObjectError 异常。此时,如果尚未达到容量,则将再次重试整个过程。

更新#2

继@kenn 的回复之后,这里更新了 SheduledRun 对象上的参加方法:

0 投票
0 回答
1567 浏览

mysql - ActiveRecord::Base.connection.update(sql) 有时会返回不正确的受影响行数

我有一个具有以下环境的生产网站:

  • 导轨 2.3.5
  • MySQL 服务器 5.1.33
  • Enterprise Ruby 1.8.6(2008-08-11 补丁级别 287)[x86_64-linux]
  • mysql 宝石 2.7
  • 旧版本的 BackgrounDRb 插件在 4 个不同的服务器上运行用于后台任务,每个有 5 个不同的工作人员(Ruby 线程,而不是单独的进程!)。

BackgrounDRb 工作人员之一使用“乐观锁定”的变体处理作业队列:

上面的代码尝试使用给定的 ID 和 in_process 字段的额外条件来更新记录。因此,如果同一记录已由不同的服务器/进程更新,则 UPDATE 语句将仅返回 0(零),并且该作业不会由 2 个不同的服务器同时处理。

问题是:有时“Job.connection.update(update_sql)”即使实际更新了记录也会返回 0(零)!只有在代码中添加了大量日志记录后,我才能发现这一点。它只发生在晚上我们负载很重的生产中......

我的猜测是 mysql gem 使用了一些全局变量(类变量)来影响 BackgrounDRb 进程的所有 5 个线程,但我不确定。我正在查看 mysql gem 和 ActiveRecord 的代码,但我不明白它是如何工作的。

这怎么可能发生?

2010-07-07 更新:我们决定不使用线程进行作业处理——这将解决我们所有的问题:每个作业处理器都是一个单独的进程 :)

0 投票
4 回答
16818 浏览

java - Spring Optimistic Locking:如何重试事务方法直到提交成功

我将 Spring 2.5 和 Hibernate JPA 实现与 Java 和“容器”托管事务一起使用。

ConcurrencyFailureException我有一个“用户提交后”方法,可以在后台更新数据,无论是否有异常都需要提交StaleObjectStateException,因为它永远不会显示给客户端。换句话说,需要把乐观锁变成悲观。(如果方法执行需要更长的时间并且有人在其他事务中更改了数据,则可能会发生)


我读了很多关于幂等的东西,如果在搜索 DEFAULT_MAX_RETRIES6.2.7 时出现异常,请重试。示例第 14.5 章。重试。我还在这里这里的 stackoverflow 中找到了。

我试过这个:

RetryOnConcurrencyException是我的注释,用于标记发生异常时需要重试的方法。没用...我也尝试了几种方法SELECT ... FOR UPDATE,例如EntityManager.lock(...)

使用 Spring 避免过时数据、脏读等策略的最佳方法是什么?重试?,同步?,JPA 锁定?,隔离?,选择...进行更新?我无法让它工作,我对任何帮助感到非常高兴。


这是我喜欢做的一些伪代码:

在 // XXX 和 // YYY 之间,另一个会话可以修改项目,然后抛出 StaleObjectStateException。

0 投票
2 回答
2128 浏览

hibernate - ReSTful 应用程序中的服务器端乐观锁定:处理来自同一客户端的异步请求

我正在从事一个项目,该项目正在从概念验证过渡到值得试点项目的东西。这一开发阶段的关键改进之一是从当前的“持久性”机制(使用保存在内存中并定期转储到文件中的哈希表)转向更传统的数据库后端。

应用程序本身的设计考虑了ReSTful原则。它使用 Jersey 提供对资源的访问,使用 jQuery 向用户呈现这些资源并启用基本交互(创建、更新、删除)。很直接。

我过去曾成功使用 JPA 和 Hibernate 将服务器端状态持久保存在关系数据库中,因此在这种情况下,这似乎是一个自然的选择。通过对模型实体进行一些小的更改,我能够在合理的时间内完成基本的读取、创建和删除操作。然而,更新操作被证明更加困难。

在用户修改资源几秒钟后,应用程序的客户端部分会自动将更改发送到服务器。此外,还有一个“保存并关闭”按钮,用户可以在返回主页之前立即将最新版本的资源发送到服务器。

我的第一个问题是如何使用来自客户端的非托管对象更新数据库中的托管实体。由于发送到客户端的数据故意省略了数据库键,这有点乏味,因为它归结为将非托管对象中的元素显式“合并”到 Hibernate 对象中。这不是我的问题,但如果有人知道一种优雅的方式来做到这一点,我很想听听。

我的第二个问题,也是这篇文章的目标,发生在我按下“保存并关闭”按钮的同时,我之前提到的自动保存操作正在进行。通常,我得到一个乐观锁定异常。这是因为第二个更新操作正在一个单独的线程中处理,而第一个更新操作仍在处理中。

该资源具有每次处理更新时设置的“更新”时间戳,因此每次都可以保证对数据库的更新,即使没有任何更改。这本身可能是一个问题,但即使在我修复它之后,仍然有一个“机会之窗”,用户可以在自动保存过程中进行修改并将其发送到服务器,从而触发同样的问题.

我能想到的解决此问题的最简单方法是重新编写一些客户端 Javascript,以确保该客户端在任何时间点都只有一个未完成的“更新”操作。(请注意,如果不同的客户端碰巧同时更新相同的资源,乐观锁定异常是完全可以的。)但是,我担心在客户端上强制执行此限制可能会偏离 ReST 的精神。期望给定客户端在 ReSTful 应用程序中的任何时间点对特定资源的未完成“更新”(PUT)请求不超过一个是否合理?

这似乎是一个相当普遍的情况,但我无法找到关于如何最好地处理它的明确答案。我考虑和放弃的其他想法包括以某种方式序列化来自同一客户端的请求(可能基于 HTTP 会话),以便按顺序处理它们,为 JPA/Hibernate 工作线程实现更新“队列”,并插入新的“版本”的资源,同时跟踪最新的而不是更新任何单个记录。

有什么想法吗?客户端的“一次一个未完成的更新”限制是否合理,还是有更好的方法?

0 投票
2 回答
869 浏览

java - 如何引发 OptimisticLockException

无法捕获乐观锁异常。

引发 OptimisticLockException 的一种方法是使用 em.flush()

但我不认为这是最好的解决方案,因为在这个完整的数据库中是刷新的。

另一种解决方法是捕捉EJBException并找到RollBackException那个..

请帮助您有任何其他想法或告诉我哪种方式更好。

0 投票
2 回答
3611 浏览

hibernate - Null @Version 列的 org.springframework.transaction.UnexpectedRollbackException

我正在使用 Spring 3.0.4-RELEASE、JPA 2.0 和 Hibernate 作为提供者,以及 JTA JOTM 用于我的应用程序中的事务。entityManager.merge调用我的实体对象时收到以下错误:

此错误是由于通过我们的 Talend ETL 作业将数据直接插入数据库 (MySQL) 造成的。我注意到我@Version在数据库中的列有NULL值,并决定将它们设置为 0,这解决了问题。

为什么不能@VersionNULL?有没有其他人遇到过这个问题?谢谢。

0 投票
6 回答
1559 浏览

testing - 如何对 Grails 应用程序进行并发修改测试

我想运行模拟用户同时为 grails 应用程序修改某些数据的测试。

我可以使用任何插件/工具/机制来有效地做到这一点吗?它们不必是特定于 grails 的。应该可以并行触发多个动作。

我更喜欢在功能级别上运行测试(到目前为止,我正在使用 Selenium 进行其他测试)以从用户的角度查看结果。当然,如果您建议在集成级别上运行并发修改测试,那么这可以在集成测试之外完成。

0 投票
1 回答
3680 浏览

hibernate - 如何克服 grails 服务中的 StaleObjectStateException

我引入了一个 TransactionService,我在控制器中使用它来执行乐观事务。它应该

  • 尝试执行给定的事务(=关闭)
  • 如果失败则回滚
  • 如果失败再试一次

它基本上看起来像这样:

它有点复杂,例如,它在重试之前使用不同的 Thread.sleeps 并在某个阶段中止,但这并不重要。它是从传递事务以作为闭包安全执行的控制器调用的。

我的问题:当服务由于并发更新而遇到 org.hibernate.StaleObjectStateException 时,它会继续重试,但异常永远不会消失。

我已经尝试了不同的方法,例如在控制器传递的事务中重新附加域类,清除服务或控制器中的会话,但没有帮助。我错过了什么?

我应该注意到,当我尝试在使用 status.createSavepoint() 调用 transaction() 之前插入 savePoint 时,我收到一个错误,即“事务管理器不允许嵌套事务”。我尝试了这个,因为我还怀疑存在错误,因为事务是从控制器传递到服务的,并且我需要启动一个新的/嵌套事务来避免它,但是由于错误表明这在我的情况下是不可能的。

或者也许将交易作为闭包传递是问题?

我假设在 .withTransaction 之前使用的域类无关紧要,或者是吗?

0 投票
1 回答
1751 浏览

oracle - 休眠Oracle 数据库的映射导致 StaleStateException

我们有一个 NHibernate 应用程序,我们正在从 SQL Server 迁移到 Oracle。我们的乐观并发是通过<timestamp name="Version">映射元素实现的。

Oracle中对应Version列的数据类型为DATE. 保存对象后,内存中的 C# 对象会留下一个以毫秒为单位的时间戳值(例如 12:34:56.789),而数据库中的值仅精确到秒(例如 12:34:56)。因此,如果我们第二次尝试保存对象,我们会收到 StaleStateException,因为这两个值不匹配。

我试图通过将Version列的数据类型更改为TIMESTAMP(3). 不幸的是,C# 对象和 DB 值仍然相差一毫秒(例如 12:34:56.789 与 12:34:56.788),因此第二次尝试保存对象仍然会导致 StaleStateException。

我可以做些什么来创建<timestamp>到类型的 Oracle 列的工作映射,DATE或者TIMESTAMP可以多次保存同一个对象?

谢谢。

——布赖恩