并发访问的SQL数据 - StaleObjectStateException

时间:2015-08-19 12:36:57

标签: hibernate grails hql gorm concurrentmodification

class Document{
     hasMany{ changes: PendingChange}
}

class DocumentService{
     def acceptAll(){
        def owner = Document.get(params.id)
        def changes = owner.changes.findAll{it.status == "pending"}.collect{it.id}
        executorWrapperService.processClosure({
        changes.each{pc -> //*1 
                changeService.accept(pc)
            }
        }, owner)
        redirect(url: request.getHeader('referer'))

     }
}

class DocumentController{
    def index(){
        def result = [:]
        def owner = Document.get(params.id)
        //even if processing running, we want to show how many are left. Accept/Reject buttons will be disabled if processingpc is true
        result.changes = owner.changes.findAll{it.status == "pending"}
        if(executorWrapperService.hasRunningProcess(owner)){ //*2
          result.processingpc = true
        }
        .
        .
        .
        return result
    }
}

class ExecutorWrapperService {

    def executorService
    ConcurrentHashMap<Object,java.util.concurrent.FutureTask> activeFuture = [:]

    def processClosure(clos,owner){
        owner = "${owner.class.name}:${owner.id}"
        //see if we got a process running for owner already
        def existingFuture = activeFuture.get(owner)
        if(!existingFuture){
            //start new thread and store the process
              def future = executorService.submit(clos as java.util.concurrent.Callable)
              activeFuture.put(owner,future)
        }else{
            //if a previous process for this owner is done, remove it and start new one
            if(existingFuture.isDone()){
                activeFuture.remove(owner)
                processClosure(clos,owner)
            }
            //if not done, do something else
        }
    }

    def hasRunningProcess(owner){
        owner = "${owner.class.name}:${owner.id}"
        // There is no process running for this owner
        if(activeFuture.get(owner) == null){
            return false
        // there was a process, but now its done.
        }else if(activeFuture.get(owner).isDone()){
            activeFuture.remove(owner)
            return false
        // we have a running process
        }else if(activeFuture.get(owner).isDone() == false){
            return true
        }
    }
}

上面的代码演示了正在发生的事情。在我的索引屏幕上,我显示了一个更改列表。当用户点击accept all按钮时,系统会调用DocumentService.acceptAll。然后创建一个新线程并开始应用更改。这对数据库对象有影响。该请求被重定向到index。因为我想在处理过程中禁用对挂起更改的任何操作,ExecutorWrapperService.activeFuture用于告诉DocumentController是否存在该文档的处理。执行DocumentController.index时,我只读取数据库字段以供显示,不会发生任何写入。

执行上述操作时,偶尔会出现以下错误之一:

events.PatchedDefaultFlushEventListener  - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Document#1495] 

在线* 1,或在线* 2上的相同错误。 我相信这与我正在创建的线程有关。 我试图想象我应该如何使用事务或会话来解决这个问题,但还没有做到。

0 个答案:

没有答案