#grails #transactions #spring-transactions #grails3
#grails #транзакции #spring-транзакции #grails3
Вопрос:
После обновления с 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
действие с тем же параметром, Rooplan устанавливается правильно.
Вызов getErrors()
внутри контроллера выдает следующее сообщение об ошибке:
Не удалось получить текущий сеанс гибернации; вложенным исключением является org.hibernate.Исключение HibernateException: сеанс не найден для текущего потока
который имеет свое происхождение от grails.артефакт.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. Если мы удалим аннотацию и снова произойдет сбой.
Мы не смогли увидеть проблему ни в одном другом контроллере и не смогли воспроизвести ее в небольшом тестовом проекте. Мы уже пытались перестроить проект, также на совершенно новой рабочей станции мы не были.
Кто-нибудь еще наблюдал такую проблему?
Комментарии:
1. Возможно, я что-то здесь упускаю (многие люди выполняют сервисную работу в контроллере). разве транзакционный не должен использоваться в контексте сервисов? Не говорить о том, что вы подняли, не является допустимым вопросом. Просто вокруг наилучшего подхода и правильного использования
2. Вы правы, но контроллеры, созданные Grails, включают аннотации. Я предполагаю, что это связано с тем, что в настоящее время нет сценария, который автоматически создавал бы соответствующую службу, только пустую, поэтому логика, должно быть, заключалась в том, что лучше иметь правильное разграничение транзакций (действия сохранения / обновления / удаления имеют @Transactional, а остальные имеют @Transactional (только для чтения = true)) в неправильном месте, чем вообще ничего.
3. действие отображает только некоторые данные модели, поэтому, IMHO, отдельная служба не нужна и накладна. Возможно, я ошибаюсь, но это способ, который предлагается из сгенерированных контроллеров grails, как указал Берт Беквит.
4. Я бы не сказал, что это вообще «предлагается». Это просто так. «Рекомендуемый» и «правильный» способ на самом деле заключается в использовании сервиса. Накладные расходы на наличие и использование сервиса настолько малы по сравнению с общим приложением, что это смешно.
Ответ №1:
Я не думаю, что вам даже понадобится @Transactional(только для чтения = true) в контроллере.
Контроллеры Grails по умолчанию доступны только для чтения. Вы можете просто удалить аннотацию из контроллера.
Напротив, класс обслуживания Grails по умолчанию является транзакционным. Если вам нужно вызвать метод save(), более желательно вызвать этот метод в классе service .
Комментарии:
1. Без @Transactional привязка к данным классов домена не работает, поскольку контроллеры по умолчанию не являются транзакционными. Вопрос в том, заметил ли кто-нибудь еще проблему, заключающуюся в том, что транзакционная аннотация уровня класса применяется не ко всем действиям
2. Я не думаю, что @Transactional имеет какое-либо отношение к привязке данных к свойствам классов домена. Когда я применил транзакционную аннотацию уровня класса, она применяется ко всем действиям. Проверьте свои правила сопоставления URL-адресов, чтобы убедиться, что правило, применимое к show(), также применимо к getRooms()
3. ну, ЭТО актуальная проблема, заключающаяся в том, что аннотация уровня класса не применяется. работает в grails 3.1.x, сбой в 3.2. По крайней мере, для этого контроллера. Мы не можем наблюдать или воспроизводить ошибку в других контроллерах. Поскольку мы не можем воспроизвести проблему в тестовом проекте, мы не можем создать тикет проблемы в проекте grails, и мы спрашиваем здесь, наблюдает ли кто-нибудь ту же проблему, чтобы найти ее первопричину.