@Transactional применяется не ко всем действиям контроллера

Мы заметили, что после обновления Grails 3.1.11 до 3.2.0 одно действие контроллера больше не работает:

@Transactional(readOnly = true)
class RoomPlanController {
    ...
    def show(RoomPlan roomPlan) {
        ...
    }
    def getRooms(RoomPlan roomPlan) {
        ...
    }
}

Проблема в том, что когда мы вызываем roomPlan/getRooms/1, roomPlan равно нулю. Если мы вызываем действие show с тем же параметром, roomPlan устанавливается правильно.

Вызов getErrors() внутри контроллера дает нам следующее сообщение об ошибке:

Не удалось получить текущий сеанс гибернации; вложенным исключением является org.hibernate.HibernateException: сеанс не найден для текущего потока

который происходит от grails.artefact.Controller.initializeCommandObject. После еще одной отладки я заметил разницу в трассировке стека между show и getRooms.

Трассировка стека show:

show:100, RoomPlanController (at.byte_code.businessSuite.hotel)
$tt__show:-1, RoomPlanController (at.byte_code.businessSuite.hotel)
doCall:-1, RoomPlanController$_show_closure13 (at.byte_code.businessSuite.hotel)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)

Трассировка стека getRooms:

getRooms:109, RoomPlanController (at.byte_code.businessSuite.hotel)
getRooms:-1, RoomPlanController (at.byte_code.businessSuite.hotel)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)

Сообщение об ошибке и другая трассировка стека позволяют предположить, что это как-то связано с сеансом/транзакцией базы данных, и после добавления @Transactional(readOnly = true) к действию все работает, как и ожидалось, и до обновления до grails 3.2.0. Если мы удалим аннотацию и снова произойдет сбой.

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

Кто-нибудь еще наблюдал такую ​​проблему?


person Andreas    schedule 08.10.2016    source источник
comment
Может быть, я что-то здесь упускаю (многие люди, работающие в сфере обслуживания, работают с контроллером). не следует ли использовать транзакцию в контексте услуг? Не говорить о том, что вы подняли, - неправильный вопрос. Просто вокруг наилучшего подхода и правильного использования   -  person V H    schedule 08.10.2016
comment
Вы правы, но контроллеры, созданные Grails, содержат аннотации. Я предполагаю, что это связано с тем, что в настоящее время нет скрипта, который будет автоматически генерировать соответствующую службу, только пустой, поэтому логика должна была заключаться в том, что лучше иметь правильное разграничение транзакций (действия сохранения/обновления/удаления имеют @Transactional и остальные иметь @Transactional(readonly=true)) не в том месте, чем вообще ничего.   -  person Burt Beckwith    schedule 08.10.2016
comment
действие отображает только некоторые данные модели, поэтому ИМХО отдельная служба не нужна и накладна. Возможно, я ошибаюсь, но это способ, который предлагается из сгенерированных контроллеров Grails, как указал Берт Беквит.   -  person Andreas    schedule 09.10.2016
comment
Я бы не сказал, что это вообще предлагается. Это просто так. Предлагаемый и правильный способ на самом деле состоит в том, чтобы использовать услугу. Накладные расходы на наличие и использование службы настолько малы по сравнению с приложением в целом, что это смехотворно.   -  person Joshua Moore    schedule 09.10.2016


Ответы (1)


Я не думаю, что вам даже понадобится @Transactional(readOnly = true) в контроллере.

Контроллеры Grails по умолчанию доступны только для чтения. Вы можете просто удалить аннотацию из контроллера.

Напротив, класс обслуживания Grails по умолчанию является транзакционным. Если вам нужно вызвать метод save(), более желательно вызывать этот метод в сервисном классе.

person elixir    schedule 10.10.2016
comment
Без @Transactional привязка данных доменных классов не работает, потому что контроллеры по умолчанию не являются транзакционными. Вопрос в том, заметил ли кто-нибудь еще проблему, заключающуюся в том, что транзакционная аннотация на уровне класса не применяется ко всем действиям. - person Andreas; 10.10.2016
comment
Я не думаю, что @Transactional имеет какое-либо отношение к привязке данных со свойствами классов предметной области. Когда я применил транзакционную аннотацию на уровне класса, она применялась ко всем действиям. Проверьте свои правила сопоставления URL-адресов, чтобы убедиться, что правило, применимое к show(), также применимо к getRooms(). - person elixir; 10.10.2016
comment
хорошо, ЭТО фактическая проблема, что аннотация уровня класса не применяется. работает в grails 3.1.x, не работает в 3.2. По крайней мере для этого контроллера. Мы не можем наблюдать или воспроизводить ошибку в других контроллерах. Поскольку мы не можем воспроизвести проблему в тестовом проекте, мы не можем создать запись о проблеме в проекте Grails, и мы спрашиваем здесь, наблюдает ли кто-нибудь ту же проблему, чтобы найти ее основную причину. - person Andreas; 11.10.2016