Используя 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
}
}