database - 同时请求Grails org.hibernate.StaleObjectStateException

标签 database multithreading hibernate grails

我有一个带有 Controller 的应用程序。执行 Controller 的操作会使用数据库字段进行更新。一次完成一个 Action ,就可以了。但是当我同时执行两个操作时,出现org.hibernate.StaleObjectStateException错误

Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

我需要 Controller 能够处理同步 Action ,例如通过排队请求并顺序执行它们。有可能吗?还是我需要自己照顾一下?

(是否在这里使用synchronized帮助?这是正确的方法吗?)

数据库是内存/文件,因为我只做很少的工作。不必运行全面数据库。

编辑:调用“层次结构”如下:

这是入口点- Controller 。
GameController
  def doTurn() {
    String login = params.login


    // From stackoverflow
    def c = Player.createCriteria()
    def player = c.get {
        eq "login", login
        lock true
    }

    // def player = Player.findAllByLogin(login).get(0)
    PlayerChoice choice = Utils.intToChoice(Integer.parseInt(params.choice))
    int turnNumber = Integer.parseInt(params.turn)

    gameFlowService.makeTurn(player, choice, turnNumber)

    def res = new Utils().playerStateToJSON(player)
    render res as JSON
  }

它调用gameFlowService:
GameFlowService{
  def makeTurn(Player player, PlayerChoice choice, int turnNumber) {
   (...)
    Game currentGame = player.currentGame
    Turn lastTurn = currentGame.getLastTurn()
    // I do stuff with Turn (if it exists) or create it
      currentGame.createTurn()
      currentGame.getLastTurn().makeChoice(player, choice)
    if (currentGame!=null){
        currentGame.save(flush: true, failOnError: true)
    }
}

游戏:
Game {
  Player player1
  Player player2

  int turnsToBePlayed

  List turns
  static hasMany = [turns: Turn]
  static belongsTo = [tournament: Tournament]

  public void createTurn() {
    Turn turn = new Turn([game      : this,
                          turnNumber: turns.size(),
                          player1   : player1,
                          player2   : player2,
                          choice1   : PlayerChoice.CHOICE_NOT_SET,
                          choice2   : PlayerChoice.CHOICE_NOT_SET,
                          points1   : 0,
                          points2   : 0])

    this.addToTurns(turn)
    this.save(flush: true, failOnError: true)
  }
}

然后转:
class Turn {
    int turnNumber
    boolean completed = false

    Player player1
    Player player2

    PlayerChoice choice1
    PlayerChoice choice2

    int points1
    int points2

    static belongsTo = [game: Game]

    public void makeChoice(Player player, PlayerChoice playerChoice){
      // This method only changes Turn's member variables
    }
}

我只会在添加新的回合时保存Game实例-导致我相信Hibernate会自动保留任何进一步的更改。

尽管使用了锁,但我仍然遇到相同的错误(stacktrace表示它在Game:this.save(flush: true, failOnError: true)中在线发生)

编辑2:
我相信我的问题并不少见。 Controller 操作会导致数据库中的更改,并且需要以某种方式对其进行序列化。 Hibernate / Grails如何解决它?

最佳答案

考虑到2个同时访问数据库的线程,我认为您的问题如下:

  • A检索对象
  • B检索对象
  • 更新对象
  • 保存对象
  • B更新对象
  • B保存对象-> StaleObjectStateException

  • 从数据库中检索对象时,可以锁定该对象。这将导致“选择...进行更新”,请参阅以下链接以了解用法:

    http://grails.org/doc/latest/ref/Domain%20Classes/lock.html

    但是为了避免出现任何竞争情况,您必须使用lock方法作为获取方法,如下所示:
    def airport = Airport.lock(10) // lock for update
    airport.name = "Heathrow"
    airport.save()
    

    如果必须查询对象,则可以在Criteria中使用锁。

    在条件示例中:
    def c = Airport.createCriteria()
    c.get {
      eq "name", name
      lock true
    }
    

    关于database - 同时请求Grails org.hibernate.StaleObjectStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24954632/

    相关文章:

    database - Entity Framework 代码首先导致数据库访问异常

    database - 如何在数据库中正确维护 SSOT(Single Source Of Truth)?

    c# - 在 C# 中,如果程序不断输出,如何从执行的 DOS 程序中读取?

    c++ - 检查函数内的当前线程是否正常?

    c++ - (C++) 如何挂起主线程,然后在另一个线程中恢复?

    java - JpaRespository deleteBy ...在某些情况下不起作用

    java - 将 java 类映射到 Postgresql 表错误

    javascript - 无需重定向的PHP更新数据库字段

    sql - 什么是存储过程,在什么意义上与简单存储过程不同?

    java - 为什么 Hibernate 搜索速度慢?即使记录很少