Как лучше всего начинать новый сеанс или транзакцию для пакетных заданий с использованием Spring / Hibernate? - PullRequest
3 голосов
/ 17 марта 2011

У меня есть набор пакетных / cron-заданий в Java, которые вызывают мои классы обслуживания.Я также использую Hibernate и Spring.

Первоначально пакетный слой всегда создавал внешнюю транзакцию, а затем пакетное задание будет вызывать службу для получения списка объектов из БД с одним и тем же сеансом., а затем вызвать службу для обработки каждого объекта в отдельности.Для моего сервисного уровня есть совет по передаче для любого броска.Так что, если для 5-го объекта есть исключение, первые 4 объекта, которые были обработаны, тоже откатываются, потому что все они были частью одной транзакции.ненужным.Я удалил это, и теперь я вызываю службу, чтобы получить список объектов.Затем вызывается другая служба для обработки каждого объекта в отдельности, и если один из этих объектов выходит из строя, другие все равно будут сохраняться, потому что это новая транзакция / сеанс для каждого вызова службы.Но проблема, с которой я столкнулся здесь, состоит в том, что после получения списка объектов, когда я передаю каждый объект в службу для обработки, если я пытаюсь получить одно из свойств, я получаю ленивую ошибку инициализации, потому что сеанс используется для загрузки этого объекта (из списка) закрыто.

Некоторые варианты, о которых я подумал, заключались в том, чтобы просто получить список идентификаторов в пакетном задании и передать каждый идентификатор в службу, и служба извлечет весь объект в этом одном сеансе иобработайте это.Другой способ - установить для отложенной загрузки значение false для атрибутов этого объекта, но при этом все будет загружаться каждый раз, даже если иногда вложенные атрибуты не нужны.

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

Каков наилучший метод для чего-то подобного?

1 Ответ

2 голосов
/ 07 апреля 2012

Ну, я бы сказал, что вы перечислили все возможные варианты, кроме OpenSessionInView . Это поддержит ваш сеанс между транзакциями, но это трудно реализовать должным образом. Так сложно, что его считают AntiPattern многими .

Однако, поскольку вы не реализуете веб-интерфейс и не имеете дело с многопоточной средой, я бы сказал, что это путь. Это не значит, что вы передаете сущности представлениям. Вы больше всего боитесь вызова N + 1 в базу данных при выполнении итерации по коллекции, но, поскольку это задача cron, производительность может не быть серьезной проблемой по сравнению с чистотой кода. Если вы действительно обеспокоены этим, просто убедитесь, что вы получили все свои коллекции, позвонив в DAO, который может сделать выбор *.

Кроме того, вы эффективно делали Open Session In View раньше, когда вы делали все в одной транзакции. Весной сеансы открываются на основе каждой транзакции, поэтому поддержание транзакции открытой в течение длительного периода времени практически равнозначно хранению сессии в течение длительного периода времени. Единственной реальной разницей в вашем случае будет тот факт, что вы можете периодически совершать операции, не опасаясь ленивой ошибки инициализации в будущем.

Редактировать

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

Кроме того, я только что заметил, что вы упомянули об открытии транзакции в пакетном слое, а затем об открытии «мини транзакций» в сервисном слое. Это совершенно НЕ хорошая идея. Транзакции Spring, управляемые аннотациями, будут привязаны к любой открытой в данный момент транзакции в сеансе. Это означает, что транзакции, которые должны быть доступны только для чтения, внезапно станут доступными для чтения и записи, если открытая в настоящее время транзакция предназначена для чтения и записи. Кроме того, сеанс не будет сброшен до тех пор, пока внешняя транзакция в любом случае не будет завершена, поэтому нет смысла отмечать слой Service с помощью @Transactional. Помещение @Transactional на несколько слоев создает ложное чувство безопасности.

Я на самом деле писал об этой проблеме некоторое время назад.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...