2016-03-01 4 views
1

Не существует определенного решения проблем параллелизма в Grails (2.3.7). Я перепробовал все рекомендации, но когда я нажимаю количество одновременных потоков, следующий фрагмент кода неизменно терпит неудачу:«Grails» Row был обновлен или удален другой транзакцией (или неверное отображение неверно) «

package simpledb 

import grails.transaction.Transactional 
import groovy.transform.Synchronized 
import org.apache.commons.logging.LogFactory 

@Transactional 
class OwnerService { 
    private static final myLock1 = new Object() 
    private static final myLock2 = new Object() 

    @Synchronized('myLock1') 
    static public saveOwner(def ownerName) { 
     def ownerInstance = null 
     Owner.withNewTransaction { 
      ownerInstance = Owner.findOrCreateByName(ownerName) 
      ownerInstance.save(failOnError: true, flush: true) 
     } 
     ownerInstance 
    } 

    @Synchronized('myLock2') 
    static public associateDog(def ownerId, def dogId) { 
     def lockedOwnerInstance 
     Owner.withNewTransaction { 
      lockedOwnerInstance = Owner.lock(ownerId) 
      def lockedDogInstance = Dog.lock(dogId) 
      lockedOwnerInstance.addToDogs(lockedDogInstance) 
      lockedOwnerInstance.save(failOnError: true, flush: true) 
     } 
     lockedOwnerInstance 
    } 
} 

Это не будет работать на линии «DEF lockedDogInstance = Dog.lock (dogId)»:

Error 500: Internal Server Error  

URI 
     /simpledb/JsonSlurper/api 
Class 
     org.hibernate.StaleObjectStateException 
Message 
     Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [simpledb.Dog#111] 

выше конструкция очень проста, где есть много-ко-многим отношения между владельцем и собакой:

Dog Класс:

package simpledb 

class Dog { 
    String name 
    Breed breed = null 
    Integer age = null 
    static hasMany = [owners: Owner] 
    static belongsTo = Owner 
    static mapping = { owners lazy: false } 
    static constraints = { 
     name blank: false, nullable: false, unique: true 
     breed nullable: true 
     age nullable: true 
    } 
} 

Владелец Класс:

package simpledb 

class Owner { 
    String name; 
    static hasMany = [dogs: Dog] 
    static mapping = { dogs lazy: false } 
    static constraints = { 
    } 
} 

FYI - это БД MySQL.

Любые рекомендации?

ответ

1

Хорошо, у вас здесь много чего, большинство из которых, я уверен, вы можете распоряжаться. Поэтому вместо того, чтобы пытаться это исправить, давайте разложим его до минимума и исходим оттуда:

  1. Ваши методы обслуживания не должны быть статическими.
  2. Ваш сервис уже совершает транзакции, поэтому withNewTransaction() может пойти. Вам также не нужно смывать.
  3. Нет необходимости синхронизировать методы обслуживания.
  4. Вам не нужно блокировать Dog, потому что вы не меняете его (добавление его в Owner.dogs создает запись в таблице соединений).

С учетом этих изменений, ваша служба заканчивает тем, как это:

package simpledb 

import grails.transaction.Transactional 
import org.apache.commons.logging.LogFactory 

@Transactional 
class OwnerService { 

    def saveOwner(def ownerName) { 
     def ownerInstance = Owner.findOrCreateByName(ownerName) 

     ownerInstance.save(failOnError: true) 
     ownerInstance 
    } 

    def associateDog(def ownerId, def dogId) { 
     def ownerInstance = Owner.lock(ownerId) 
     def dogInstance = Dog.read(dogId) 

     ownerInstance.addToDogs(dogInstance) 
     ownerInstance.save(failOnError: true) 
     ownerInstance 
    } 
} 

Посмотрите, как далеко, что принимает вас. Вы даже можете удалить замок владельца.

+0

Спасибо @ Emmanuel-Rosa за ваш ответ. Я внес изменения, которые вы рекомендовали (это то, с чего я начал). Однако я продолжаю получать такое же сообщение об ошибке, как указано выше. На этот раз несколько потоков не срабатывают при этой ошибке по сравнению с случайным потоком из моего вышеперечисленного кода. Как-то, когда дело доходит до одновременных модификаций БД, Grails не работает, как задокументировано. –

+0

Что это за приложение, которое позволяет нескольким потокам пытаться обновить одну и ту же модель домена? –

+0

Приложение по существу принимает запросы REST с полезной нагрузкой JSON и сохраняет их в базе данных. Однако перед созданием записи нам нужно проверить, существуют ли данные, и в этом случае данные необходимо обновить. Я использую JMeter для проверки кода, поскольку он позволяет имитировать многопоточные вызовы. –

 Смежные вопросы

  • Нет связанных вопросов^_^