Используя runAsync плагина Grails Exector Plugin, зачем мне нужна транзакция для сохранения объекта Domain?

Вот примерно то, что я делаю в сервисе:

runAsync 
{
  <some work here>
  myDomainObject.merge()     
}

Я получаю сообщение об ошибке "Сессия Hibernate не привязана к потоку, и конфигурация не позволяет создавать нетранзакционный сеанс здесь". Я точно знаю, что код выполняется асинхронно, поэтому может показаться, что плагин Executor настроен правильно.

Поэтому я попытался сделать это следующим образом, думая, что объект домена "myDomainObject" не должен быть связан в этом потоке, хотя поток имеет сеанс гибернации благодаря плагину executor:

runAsync
{
  <work>
  def instance2= MyDomainObject.get(myDomainObject.id) // works
  instance2.field1=123
  instance2.save() // fails
}

Я получаю ту же ошибку здесь и, что интересно, get() успешно переносит правильные данные и устанавливает их в instance2. Это только "save()", который терпит неудачу. Я знаю это, потому что я прошел через код в отладчике.

Наконец, если я сделаю следующее, все работает:

runAsync 
    {
      <some work here>
      MyDomainObject.withTransaction {
           myDomainObject.field1=123
           myDomainObject.merge()
      }
    }

Я не понимаю, почему эта транзакция требуется, поскольку я не настроил службу, в которой пишу приведенный выше код, как транзакционную. Я знаю, что должно быть что-то фундаментальное, чего я не знаю здесь, но я не могу понять, что это такое.

1 ответ

Похоже, вы ответили на свой вопрос:)

Я не понимаю, почему эта транзакция требуется, поскольку я не настроил службу, в которой пишу приведенный выше код, как транзакционную.

Посмотрите на ПРИМЕЧАНИЕ ПО СДЕЛКАМ. Вам нужен ваш сервис, чтобы быть транзакционным.

ЗАМЕЧАНИЕ ПО СДЕЛКАМ: имейте в виду, что это приводит к появлению нового потока и что любой вызов будет вне транзакции, в которой вы находитесь. Используйте.withTransaction внутри вашего замыкания, выполняемого или вызываемого, чтобы ваш процесс выполнялся в транзакции, которая не является вызов метода транзакционной службы (например, при использовании этого в контроллере).

ОБНОВИТЬ
Попробуйте класс обслуживания, как показано ниже:

class MyService{

    def someMethod(){
        runAsync {
            anotherMethod()
        }
    }

    def anotherMethod(){ 
       <work>
       def instance2= MyDomainObject.get(myDomainObject.id) // works
       instance2.field1=123
       instance2.save() // should work as well
    }
}
Другие вопросы по тегам