DAO, Spring и Hibernate - PullRequest
       15

DAO, Spring и Hibernate

7 голосов
/ 15 марта 2010

Поправь меня, если что-то не так.

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

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

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

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

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

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

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

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

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

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

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

Логика и транзакции инкапсулированы в DAO, верно?

Ответы [ 4 ]

6 голосов
/ 15 марта 2010

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

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

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

Затем, когда вы возвращаете такую ​​сущность, ленивое поле уже инициализировано.

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

5 голосов
/ 15 марта 2010

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

1 голос
/ 01 сентября 2016

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

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();
}
1 голос
/ 09 августа 2011

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

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