2010-03-15 2 views
7

Исправьте меня, если что-то не так.DAO, Spring и Hibernate

Теперь, когда мы используем Spring DAO для шаблонов ORM, когда мы используем атрибут @Transactional, , у нас нет контроля над транзакцией и/или сеансом, когда метод вызывается извне, а не внутри метода.

Lazy loading сохраняет ресурсы - меньше запросов к db, меньше памяти, чтобы сохранить все коллекции, извлеченные в памяти приложения.

Итак, если lazy = false, тогда все будет выбрано, все связанные коллекции, что не эффективно, если в связанном наборе есть 10 000 записей.

Теперь у меня есть метод в классе DAO, который должен вернуть мне объект User. В нем есть коллекции, которые представляют связанные таблицы базы данных. Мне нужно получить объект по id, а затем запросить его коллекции.

Hibernate «не удалось лениво инициализировать сбор». Исключение возникает, когда я пытаюсь получить доступ к связанной коллекции, которую возвращает этот метод DAO.

Объясните пожалуйста, что такое обходной путь здесь?

Обновление: Хорошо, позвольте мне спросить вас об этом. DAO - абстрактный уровень, поэтому метод getUserById (Integer id) должен возвращать объект.

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

Есть только два пути: 1) ленивы погрузочные = ложь 2) создавать различные методы: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() и внутри этих методов используют свой подход?

Я имею в виду, что есть только два пути и ничего лучше?

Обновление 2: Объясните пожалуйста, что даст мне явное использование SESSIONFACTORY? Как это выглядит на практике? Мы создаем экземпляр объекта DAO, , затем вводим его фабрикой сеансов, и это означает, что два последовательных метода вызова для DAO будут выполняться в рамках одной транзакции? Мне кажется, что DAO отделяется от классов, которые его используют!

Логика и транзакции заключены в DAO, правильно?

ответ

6

Вы можете получить связанную коллекцию в сделке, чтобы загрузить его в то время как вы все еще внутри транзакции:

User user = sessionFactory.getCurrentSession().get(User.class, userId); 
user.getLinkedCollection().size(); 
return user; 

Как BalusC указал, вы можете использовать Hibernate.initialize() вместо size(). Это намного чище.

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

Ответ на ваш PS - использование транзакций на уровне обслуживания (а не DAO) возможно? Кажется, что, поскольку каждый вызов DAO в отдельной транзакции кажется пустой тратой (и может быть неправильной).

+0

@ Konrad Garus См. Мой постскриптум вопроса, здесь текст менее читабельен, поэтому я прошу вас там. – EugeneP

+0

@EugeneP См. Обновленный ответ. –

5

Я считаю, что лучше использовать @Transactional на уровне сервиса, а не в слое DAO. В противном случае все ваши вызовы DAO находятся в отдельных сеансах спящего режима - все эти вещи равенства объектов не будут работать.

+1

Это хороший способ справиться с этим при работе с SpringDAO. –

1

На мой взгляд, лучший способ решить эту проблему - создать приложение в модели с сеансом за запрос. Затем, если у вас даже есть объект, взятый из DAO, пока ваш шаблон OSIV не работает, вы можете безопасно использовать объект в любом месте приложения, даже в представлениях, не беспокоя этого. Это, вероятно, лучшее решение, что те предложили, потому что:

  1. Hibernate.initialize() или размер очень искусственный обходной - что, если вы хотите, чтобы пользователь с другой коллекцией, инициализирован, вы бы написать еще один способ для получения пользователем?
  2. Service слой транзакционной модели в порядке, но та же проблема возникает, когда вы хотите получить объект, извлеченный из сервисного слоя, чтобы использовать его в контроллере или представлении
1

Вы могли бы сделать что-то вроде следующего:

public User getByUserId(Long id, String ... fetch) { 
    Criteria criteria = createCriteria(); 

    if (fetch != null) { 
     for (String fieldName : fetch) { 
      criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly 
     } 
    } 
    return criteria.add(Restrictions.eq("id", id)).list(); 
} 
Смежные вопросы