Я прочитал немного о том, как настроить транзакции для соединения Spring и Hibernate вместе.Похоже, рекомендуемый подход заключается в инициализации транзакций на уровне сервиса.
Определенно.Разграничение транзакций должно выполняться на уровне сервисного уровня, а не на уровне DAO:
- единицей работы является сервис, а не DAO
- , для которого требуется охват транзакциинесколько DAO, если требуется.
Что мне не нравится, так это то, что большинство транзакций существуют только потому, что они необходимы для правильной работы спящего режима.
Вам следуетвозможно, разработайте эту часть, потому что транзакции не являются специфичными для Hibernate.
И когда мне действительно нужна транзакция для задания, вызывающего несколько методов обслуживания, кажется, что у меня нет выбора продолжать инициализировать транзакции из заданий.
Если вы хотите вызывать несколько сервисов внутри транзакции, инициированной на уровне заданий, объявите свои сервисы как транзакционные с семантикой REQUIRED
(по умолчанию) и полагайтесь на транзакцию Springраспространение (это применимо, если вам не нужен удаленный вызов; в этом случае используйте EJB).
Таким образом, перемещение @Transactional аннотаций из DAO в сервис, кажется, не имеет никакого значения.
Это действительно имеет значение, и фактто, что вам нужно инициировать транзакции из уровня Job, когда запуск пакетов не меняет дело.
Я настоятельно рекомендую прочитать Глава 9. Управление транзакциями .
(...) моя главная проблема связана с Hibernate.Извините, если мне не ясно.
Нет проблем.Просто когда вопрос неопределенный, вы часто получаете расплывчатый ответ:)
Из документации гибернации: «Транзакции с базой данных никогда не являются необязательными. Все взаимодействие с базой данных должно происходить внутри транзакции».,Вот почему разработчики помещают методы DAO на мой проект.
Извините, но вышеприведенное утверждение только говорит о том, что "связь с базой данных должна происходить внутри транзакции" , ничего более, и решение о том, кудаСтарт транзакции остается на ваше усмотрение (обычно это сервисный уровень).Если вы сделаете это на уровне DAO, что если MySuperService
вызовет DaoFoo
и DaoBar
и DaoBar
не удастся?В таких случаях вы, вероятно, захотите откатить все изменения, а не только те, которые были выполнены в DaoBar
.Отсюда необходимость контролировать транзакцию, с которой начинается единица работы.
ИМХО, разработчикам нужно какое-то руководство.
Значит ли это, что все мои сервисы должны быть транзакционными?Даже когда я просто читаю данные, например?
Прежде всего, я предлагаю прочитать Нетранзакционный доступ к данным и режим автоматической фиксации (младший брат Сеансов и транзакций ) дляуточнить вещи о «транзакции только для чтения» .Чтение всей страницы того стоит, но позвольте мне процитировать эту конкретную часть:
Многие разработчики приложений считают, что они могут общаться с базой данных вне транзакции.Это, очевидно, невозможно; оператор SQL нельзя отправить в базу данных вне транзакции базы данных .Термин «нетранзакционный доступ к данным» означает, что нет никаких явных границ транзакции, нет системной транзакции, и что поведение доступа к данным такое же, как в режиме автоматической фиксации.Это не означает, что никакие физические транзакции с базой данных не участвуют.
Как только вы закончите с вышеуказанной ссылкой, следующее предлагаемое чтение будет @ Транзакционные ошибки флага только для чтения .Вот соответствующая часть:
(...) Суть в том, что при использовании платформы на основе ORM флаг только для чтения совершенно бесполезен и в большинстве случаев игнорируется.Но если вы все еще настаиваете на его использовании, всегда устанавливайте режим распространения на SUPPORTS, так как shсобственные в листинге 9, поэтому нет транзакций
запущено:
Листинг 9. Использование режима чтения только для чтения и SUPPORTS
для выбора
работа
@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
Еще лучше, просто избегайте использования
@Transactional
аннотация в целом
при выполнении операций чтения, как показано
в листинге 10:
Листинг 10. Удаление аннотации @Transactional
для select
операции
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}