当前位置: 首页 > 知识库问答 >
问题:

Grail中的并发事务导致数据库过时状态异常

广献
2023-03-14

下面是我在api调用上运行的代码。下面的代码位于grails服务中,默认情况下是事务性的。但是,即使在锁定行之后,我也会收到这样的错误:消息:行被另一个事务更新或删除(或未保存的值映射不正确)数据库中只有一个计划,所以for循环只运行一次。但对api的并发调用会导致错误。请帮我解决这个问题

def updateAllPlans(def user,def percentComplete,def chapterId){
        def plans = Plan.findAllWhere(user:user)
        def chapter = Chapter.findById(chapterId)
        for(def plan:plans){
                def foundChapters = plan.psubject.ptopics.psubtopics.pchapters.chapter.flatten().contains(chapter)
                if(foundChapters){
                    plan.lock()
                    if(percentComplete=='0'){
                        plan.durationViewComplete = plan.durationViewComplete.plusMillis(chapter.duration.getMillisOfSecond())
                        plan.durationViewComplete = plan.durationViewComplete.plusSeconds(chapter.duration.getSecondOfMinute())
                        plan.durationViewComplete = plan.durationViewComplete.plusMinutes(chapter.duration.getMinuteOfHour())
                        plan.durationViewComplete = plan.durationViewComplete.plusHours(chapter.duration.getHourOfDay())
                    }else{
                        plan.durationComplete = plan.durationComplete.plusMillis(chapter.duration.getMillisOfSecond())
                        plan.durationComplete = plan.durationComplete.plusSeconds(chapter.duration.getSecondOfMinute())
                        plan.durationComplete = plan.durationComplete.plusMinutes(chapter.duration.getMinuteOfHour())
                        plan.durationComplete = plan.durationComplete.plusHours(chapter.duration.getHourOfDay())
                    }

                    plan.save(flush:true, failOnError:true)
                }
        }
    }

共有1个答案

漆雕成弘
2023-03-14

您只能在计划被读取后锁定它。因此多个线程可以同时读取计划。然后一个线程锁定它并更新它,另一个线程锁定它并更新它。但是它们都是同时读取的,所以两者都读取相同的数据,里面有相同的版本:

thread 1: read plan, with version = 3
thread 2: read plan, with version = 3
thread 1: lock plan
thread 1 : update and save plan. version becomes 4
thread 2 : lock plan
thread 2 : update and save plan. version in memory is 3, but version in database is 4, so an exception is thrown

您需要在阅读时锁定(这是悲观锁定),如文档所示:

def airport = Airport.findByName("Heathrow", [lock: true])

然后,第二个线程必须等待第一个线程保存并提交其事务,然后再读取相同的计划。

然而,这也有悲观锁的所有缺点:吞吐量可能会降低,因为一次只有一个事务可以使用该计划,而这正是乐观锁试图避免的。代价是您可能会得到异常,并且必须处理它们(通过重试、显示错误消息,或者根据情况选择最佳答案)

 类似资料:
  • 我正在与用propagation.requires_new注释的方法的奇怪行为作斗争。 以下是TransactionManager的日志:

  • 我一直试图运行事务方法,但它无法在firebase数据库中获取和设置正确的数据。 代码如下:

  • 问题内容: 我试图在表上执行一些DDL,并导致出现“正在等待表元数据锁定”消息。 我如何找出尚未关闭的交易? 我正在使用MySQL v5.5.24。 问题答案: 寻找部分- 我们可以使用 INFORMATION_SCHEMA 表。 有用的查询 要检查所有锁事务正在等待: 阻止交易的列表: 要么 特定表上的锁列表: 等待锁的事务列表: 参考 - MySQL的故障排除:怎么办时,查询不工作,第6章-第

  • #全局事务状态表 状态 代码 备注 全局事务开始(Begin) 1 此状态可以接受新的分支事务注册 全局事务提交中(Committing) 2 这个状态会随时改变 全局事务提交重试(CommitRetry) 3 在提交异常被解决后尝试重试提交 全局事务回滚中(Rollbacking) 4 正在重新回滚全局事务 全局事务回滚重试中(RollbackRetrying) 5 在全局回滚异常被解决后尝试事

  • 我正在开发一个web应用程序,使用React跟踪水果供应商的库存。js,MongoDB,Node。js和Express。我调用了数据库endpoint来呈现表中的数据。现在,我尝试使用按钮增加和减少库存量,但当我尝试设置新状态时,它不起作用。我尝试通过单击更改状态,然后更新数据库中的新状态。有什么建议吗? > 可结果成分: 从'react'导入Reac,{Component};从“react bo

  • 在数据库中,事务可以处于以下状态之一 - 1. 活动状态 活动状态是每个事务的第一个状态。 在此状态下,正在执行事务。 例如: 在此处完成插入或删除或更新记录。 但是所有记录仍未保存到数据库中。 2. 部分提交 在部分提交状态下,事务执行其最终操作,但数据仍未保存到数据库中。 在总标记计算示例中,在该状态下执行总标记步骤的最终显示。 3. 提交 如果事务成功执行所有操作,则称该事务处于已提交状态。