http://dr-magic.blogspot.ru/2010/01/hibernate-4.html
Разница между Hibernate openSession() и getCurrentSession()
В литературе по Hibernate сессия определяется как часть работы (unit of work). Как определить границы этой части? Hibernate нас тут не ограничивает. Можно связать сессию с транзакцией базы данных (на каждую транзакцию открываем новую сессию), однако разработчики фреймворка дают нам возможность в рамках одной сессии проводить несколько транзакций. Теоретически мы можем для всех взаимодействий с базой данных использовать одну сессию (например, для однопользовательского приложения). Ну, это конечно из раздела bad practice, я просто хотела сказать, что разработчик сам решает что считать логической частью работы, и когда открывать-закрывать сессию. Для обеспечения такой гибкости используется openSession()
Однако в большинстве случаев можно выделить единую стратегию открытия-закрытия сессии. Например, для каждой транзакции базы данных открывается или закрывается своя сессия. Или сессия открывается для каждого потока. Для того чтобы реализовать такую единую стратегию открытие сессии делегируется специальному классу (этот класс должен реализовать интерфейс CurrentSessionContext
http://ajava.org/online/hibernate3api/org/hibernat...ext/CurrentSessionContext.html ). Программист лишь вызывает метод getCurrentSession(), который либо открывает новую сессию, либо возвращает нам уже существующую сессию (когда создается новая сессия - зависит от конкретной реализации CurrentSessionContext).
Кстати, американцы вместо "стратегия открытия-закрытия сессии ..." выражаются более изящно - "scopes the notion of a current session".
Еще одно преимущество использования getCurrentSession() - нет необходимости заботиться о закрытии сессии. То есть
...
session.flush();
session.close();
мы используем только для openSession(). Для getCurrentSession() сессия закрывается автоматом
В Hibernate реализации интерфейса CurrentSessionContext есть 3 штуки. Вот список с указанием, какая же стратегия открытия сессии используется в реализации:
JTASessionContext - сессия асоциируется с JTA-транзакцией. Насколько я поняла, каждой транзакции - по сессии. Поскольку я не знаю что такое JTA, ничего определенного сказать не могу. Иду изучать. Кстати, нашла в блоге упоминание о "JTA enabled container". Вообще, все что я на данный момент знаю: JTA - не JDBC Transaction.
ManagedSessionContext
ThreadLocalSessionContext - каждому треду - по сессии. Обеспечивается это путем хранения открытой сессии в переменной ThreadLocal
Тип используемой реализации указывается декларативно в файле hibernate.cfg.xml таким способом:
thread
В моем проекте для создания обьекта SessionFactory я использую Spring. В данной реализации файл hibernate.cfg.xml отсутствует, а настройка Hibernate производится в xml-файле настройки Spring. В этом случае декларация CurrentSessionContext производится так:
...
hibernate.current_session_context_class=thread
...
Решение проблемы N+1 в Hibernate
Если специально не заниматься оптимизацией, то ORM зачастую приводит к проблеме, называющейся "N+1": у нас имеются две связанные сущности (не важно 1-*, *-1 или 1-1) и дочерняя загружается лениво, то, при итерации по родительским сущностям и обращении к дочерним, будет в сумме N+1 обращений к базе, чтобы инициализировать ленивые прокси.
Объясните суть паттерна DI или IoC
Одной из реализаций IoC является внедрение зависимостей (англ. dependency injection). Внедрение зависимости используется во многих фреймворках, которые называются IoC-контейнерами.
Dependency injection (DI) - паттерн проектирования и архитектурная модель, так же известная как Inversion of Control (IoC). DI описывает ситуацию, когда один объект реализует свой функционал через другой объект. Например, соединение с базой данных передается конструктору объекта через аргумент, вместо того чтобы конструктор сам устанавливал соединение. Термин "dependency injection" немного неправильный, т.к. внедряются не зависимости, а функциональность или ресурсы. Существуют три формы внедрения (но не типа) зависимостей: сэттер, конструктор и внедрение путем интерфейса.
DI - это способ достижения слабой связанности. IoC предоставляет возможность объекту получать ссылки на свои зависимости. Обычно это реализуется через lookup-метод. Преимущество IoC в том, что эта модель позволяет отделить объекты от реализации механизмов, которые он использует. В результате мы получаем большую гибкость как при разработке приложений, так и при их тестировании.
Фабричный метод (англ. Factory Method pattern)
Service locator
Внедрение зависимости (англ. Dependency injection)
Через метод класса (англ. Setter injection)
Через конструктор (англ. Constructor injection)
Через интерфейс внедрения (англ. Interface injection)
IoC контейнер (англ. IoC-container
Какие IoC контейнеры вы знаете?
Spring является IoC контейнером. Помимо него существуют HiveMind, Avalon, PicoContainer и т.д.
Какие существуют виды DI? Приведите примеры.
Сеттер, конструктор.
Что такое Spring? Из каких частей состоит Spring Framework?
Spring - фреймворк с открытым исходным кодом, предназначеный для упрощения разработки enterprise-приложений. Одним из главным преимуществом Spring является его слоистая архитектура, позволяющая вам самим определять какие компоненты будут использованы в вашем приложении. Модули Spring построены на базе основного контейнера, который определяет создание, конфигурация и менеджмент бинов. Вот основные модули:
Основной контейнер - предоставляет основной функционал Spring. Главным компонентом контейнера является BeanFactory - реализация паттерна Фабрика. BeanFactory позволяет разделить конфигурацию приложения и информацию о зависимостях от кода.
Spring context - конфигурационный файл, который предоставляет информация об окружающей среде для Spring. Сюда входят такие enterprise-сервисы, как JNDI, EJB, интернационализация, валиадция и т.п.
Spring AOP - отвечает за интеграцию аспектно-ориентированного программирования во фреймворк. Spring AOP обеспечивает сервис управления транзакциями для Spring-приложения.
Spring DAO - абстрактный уровень Spring JDBC DAO предоставляет иерархию исключений и множество сообщений об ошибках для разных БД. Эта иерархия упрощает обработку исключений и значительно уменьшает количество кода, которое вам нужно было бы написать для таких операций, как, например, открытие и закрытие соединения.
Spring ORM - отвечает за интеграцию Spring и таких популярных ORM-фреймворков, как Hibernate, iBatis и JDO.
Spring Web module - отвечает за context web-приложений.
Spring MVC framework - реализация паттерна MVC для построения Web-приложений.
Что такое AOP? Как это относиться к IoC?
Аспектно-ориентированное программирование (АОП) — парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули. AOP и Spring - взаимодополняющие технологии, которые позволяют решать сложные проблемы путем разделения функционала на отдельные модули.
Основные понятия АОП:
Аспект (англ. aspect) — модуль или класс, реализующий сквозную функциональность. Аспект изменяет поведение остального кода, применяя совет в точках соединения, определённых некоторым срезом.
Совет (англ. advice) — средство оформления кода, который должен быть вызван из точки соединения. Совет может быть выполнен до, после или вместо точки соединения.
Точка соединения (англ. join point) — точка в выполняемой программе, где следует применить совет. Многие реализации АОП позволяют использовать вызовы методов и обращения к полям объекта в качестве точек соединения.
Срез (англ. pointcut) — набор точек соединения. Срез определяет, подходит ли данная точка соединения к данному совету. Самые удобные реализации АОП используют для определения срезов синтаксис основного языка (например, в AspectJ применяются Java-сигнатуры) и позволяют их повторное использование с помощью переименования и комбинирования.
Внедрение (англ. introduction, введение) — изменение структуры класса и/или изменение иерархии наследования для добавления функциональности аспекта в инородный код. Обычно реализуется с помощью некоторого метаобъектного протокола (англ. metaobject protocol, MOP).
Объясните работу BeanFactory в Spring.
BeanFactory - это реализация паттерна Фабрика, его функицональность покрывает создание бинов. Так как эта фабрика знает о многие объектов приложения, то она может создавать связи между объектами на этапе создания экземпляра. Существует несколько реализаций BeanFactory, самая используемся - "org.springframework.beans.factory.xml.XmlBeanFactory". Она загружает бины на основе конфигурационного XML-файла. Чтобы создать XmlBeanFactory передайте конструктору InputStream, например:
BeanFactory factory = new XmlBeanFactory(new FileInputStream("myBean.xml"));
После этой строки фабрика знает о бинах, но их экземпляры еще не созданы. Чтобы инстанцировать бин нужно вызвать метод getBean(). Например:
myBean bean1 = (myBean)factory.getBean("myBean");
В чем роль ApplicationContext в Spring?
В то время, как BeanFactory используется в простых приложениях, Application Context - это более сложный контейнер. Как и BeanFactory он может быть использован для загрузки и связывания бинов, но еще он предоставляет:
возможность получения текстовых сообщений, в том числе поддержку интернационализации;
общий механизм работы с ресурсами;
события для бинов, которые зарегестрированы как слушатели.
Из-за большей функциональности рекомендуется использование Application Context вместо BeanFactory. Последний используется только в случаях нехватки ресурсов, например при разработке для мобильных устройств. Существует 3 основных реализации Application context:
ClassPathXmlApplicationContext - получает информацию из xml-файла, находящегося в classpath. Пример: ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
FileSystemXmlApplicationContext - получает информацию из xml-файла. Например: ApplicationContext context = new FileSystemXmlApplicationContext("bean.xml");
XmlWebApplicationContext - получает информацию из xml-файла за пределами web-приложения.
Каким образом Spring поддерживает DAO?
Класс HibernateDaoSupport является подходящим суперклассом для Hibernate DAO. Он содержит методы для получения сессии или фабрики сессий. Самый популярный метод - getHibernateTemplate(), который возвращает HibernateTemplate. Этот темплейт оборачивает checked-исключения Hibernate в runtime-исключения, позволяя вашим DAO оставаться независимыми от исключений Hibernate.
Пример:
public class UserDAOHibernate extends HibernateDaoSupport {
public User getUser(Long id) {
return (User) getHibernateTemplate().get(User.class, id);
}
public void saveUser(User user) {
getHibernateTemplate().saveOrUpdate(user);
if (log.isDebugEnabled()) {
log.debug(“userId set to: “ + user.getID());
}
}
public void removeUser(Long id) {
Object user = getHibernateTemplate().load(User.class, id);
getHibernateTemplate().delete(user);
}
}
Как выглядит типичная реализция метода используя Spring?
Для типичного Spring-приложения нам необходимы следующие файлы:
1. Интерфейс, описывающий функционал приложения
2. Реализация интерфейса, содержащая свойства, сэттеры-гэттеры, функции и т.п.
3. Конфигурационный XML-файл Spring'а.
4. Клиентское приложение, которое использует функцию.
Как задаются файлы маппинга Hibernate в Spring?
Через applicationContext.xml в web/WEB-INF. Например:
?
1
2
3
4
5
org/appfuse/model/User.hbm.xml
Как добавить поддержку Spring в web-приложение
Достаточно просто указать ContextLoaderListener в web.xml файле приложения:
?
1
2
3
org.springframework.web.context.ContextLoaderListener
Можно ли использовать xyz.xml вместо applicationContext.xml?
ContextLoaderListener - это ServletContextListener, который инициализируется когда ваше web-приложение стартует. По-умолчанию оно загружает файл WEB-INF/applicationContext.xml. Вы можете изменить значение по-умолчанию, указав параметр contextConfigLocation. Пример:
?
1
2
3
4
5
6
7
8
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
/WEB-INF/xyz.xml
Как настраивается соединение с БД в Spring?
Используя datasource "org.springframework.jdbc.datasource.DriverManagerDataSource". Пример:
?
1
2
3
4
5
6
7
8
9
10
org.hsqldb.jdbcDriver
jdbc:hsqldb:db/appfuse
sa
Как сконфигурировать JNDI не через datasource в applicationContext.xml?
Используя "org.springframework.jndi.JndiObjectFactoryBean". Пример:
?
1
2
3
4
5
java:comp/env/jdbc/appfuse
Какие преимущства от использования Hibernate?
Некоторые из них:
• прозрачный механизм связи БД и POJO;
• HQL;
• автоматическая генерация primary key;
• кэш: Session Leve, Query и Second level;
• производительность: ленивая инициализация, выборка outer join.
Что такое сесиия и фаблика сессий в Hibernate? Как настроить session factory в конфигурационном файле Spring?
Hibernate сессия - это главный интерфейс взаимодействия Java-приложения и Hibernate. SessionFactory позволяет создавать сессии согласно конфигурации hibernate.cfg.xml. Например:
?
1
2
3
4
5
6 // Initialize the Hibernate environment
Configuration cfg = new Configuration().configure();
// Create the session factory
SessionFactory factory = cfg.buildSessionFactory();
// Obtain the new session object
Session session = factory.openSession();
При вызове Configuration().configure() загружается файл hibernate.cfg.xml и происходит настройка среды Hibernate. После того, как конфигурация загружена, вы можете сделать дополнительную модификацию настроек уже на программном уровне. Данные корректировки возможны до создания экземпляра фабрики сессий. Экземпляр SessionFactory как правило создается один раз и используется во всем приложении.
Главная задача сессии - обеспечить механизмы создания, чтения и удаления для экземпляров примапленых к БД классов. Экземпляры могут находиться в трёх состояниях:
1. transient - никогда не сохранялись, не ассоциированы ни с одной сессией;
2. persistent - ассоциированы с уникальной сессией;
3. detached - ранее сохраненные, не ассоциированы с сессией.
Объект Hibernate Session представляет одну операцию с БД. Сессию открывает фабрика сессий. Сессия должна быть закрыта, когда все операции с БД совершены. Пример:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 Session session = null;
UserInfo user = null;
Transaction tx = null;
try {
session = factory.openSession();
tx = session.beginTransaction();
user = (UserInfo)session.load(UserInfo.class, id);
tx.commit();
} catch(Exception e) {
if (tx != null) {
try {
tx.rollback();
} catch (HibernateException e1) {
throw new DAOException(e1.toString()); }
}
throw new DAOException(e.toString());
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) { }
}
}
В чем различие методов get() и load()?
Метод load() старее, чем get(), который был добавлен по просьбам пользователей Hibernate. Оба метода предназначены для получения объекта из БД, различие между ними тривиальное: в случае, если объект с заданным ID не будет найден в БД метод load() выбросит исключение, а get() вернет null.
Пример вычитки из БД:
?
1 User user = (User) session.get(User.class, userID);
Метод load() может вернуть прокси, вместо реального объекта. Таким образом выбор между load() и get() прост: если вы уверены, что объект существует и его отсутствие - это исключительная ситуация - используйте load(), иначе get().
Какие типы менеджмента транзакций поддерживаются в Hibernate?
Hibernate взаимодействует с БД через JDBC-соединение. Таким образом он поддерживаетуправляемые и не управляемые транзакции.
Неуправляемые транзакции в web-контейнере:
?
1
2
3
4
5
Управляемые транзакции на сервере приложений, использующий JTA:
?
1
2
3
4
5
Что такое ленивая загрузка и как её добиться в Hibernate?
Ленивая загрузка определяет будет ли дочерний объект загружен при загрузке объекта-родителя. Она настраивается свойством Lazy для дочернего объектв в файле маппинга объекта-родителя. По-умолчанию это свойство и так стоит в true.
Hibernate не поддерживает ленивую загрузку для объектов не в сессии.
Какие существуют стратегии загрузки объектов в Hibernate?
Существуют следующие типа fetch'a:
• Join fetching: hibernate получает ассоциированные объекты и коллекции одним SELECT используя OUTER JOIN
• Select fetching: использует уточняющий SELECT чтобы получить ассоциированные объекты и коллекции. Если вы не установите lazy fetching определив lazy="false", уточняющий SELECT будет выполнен только когда вы запрашиваете доступ к ассоциированным объектам
• Subselect fetching: поведение такое же, как у предыдущего типа, за тем исключением, что будут загружены ассоциации для все других коллекций, «родительским» для которых является сущность, которую вы загрузили первым SELECT’ом.
• Batch fetching: оптимизированная стратегия вида select fetching. Получает группу сущностей или коллекций в одном SELECT’е.
Какие типы кэша используются в Hibernate?
Hibernate использует 2 типа кэша: кэш первого уровня и кэш второго уровня.
Кэш первого уровня ассоциирован с объектом сесии, в то время, как кэш второго уровня ассоциирован с объектом фабрики сессий. По-умолчанию Hibernate использует кэш первого уровня для каждой операции в транзакции. В первую очередь кэш используется чтобы уменьшить количество SQL-запросов. Например если объект модифицировался несколько раз в одной и той же транзакции, то Hibernate сгенерирует только один UPDATE.
Чтобы уменьшить трафик с БД, Hibernate использует кэш второго уровня, который является общим для всего приложения, а не только для данного конкретного пользователя. Таким образом если результат запроса находится в кэше, мы потенциально уменьшаем количество транзакций к БД.
EHCache - это быстрый и простой кэш. Он поддерживает read-only и read/write кэширование, а так же кэширование в память и на диск. Но не поддерживает кластеризацию.
OSCache - это другая opensource реализация кэша. Помимо всего, что поддерживает EHCache, эта реализация так же поддерживает кластеризацию через JavaGroups или JMS.
SwarmCache - это просто cluster-based решение, базирующееся на JavaGroups. Поддерживает read-only и нестрогое read/write кэширование. Этот тип кэширование полезен, когда количество операций чтения из БД превышает количество операций записи.
JBoss TreeCache - предоставляет полноценный кэш транзакции.
Какие существуют типы стратегий кэша?
Read-only: эта стратегия используется когда данные вычитываются, но никогда не обновляется. Самая простая и производительная стратегия
Read/write: может быть использована, когда данные должны обновляться.
Нестрогий read/write: эта стратегия не гарантирует, что две транзакции не модифицируют одни и те же данные синхронно.
Transactional: полноценное кэширование транзакций. Доступно только в JTA окружении.
Как настраивается кэш второго уровня в Hibernate?
Чтобы указать кэш второго уровня нужно определить hibernate.cache.provider_class в hibernate.cfg.xml:
?
1
2
3
4
5
org.hibernate.cache.EHCacheProvider
По-умолчанию используется EHCache.
Чтобы использвать кэш запросов нужно его включить установив свойство hibernate.cache.use_query_cache в true в hibernate.properties.
Какая разница между сортированными и упорядоченными коллекциями в Hibernate?
Сортированные коллекции отсортированы в памяти используя java comparator, в то время как упорядоченные коллекции сортируются БД.
Стратеги кэширования и области
Кэширование является настолько фундаментальным понятием в объектно-реляционном отображении, что вы не сможете понять производительность, масштабируемость или семантику транзакций в реализации объектно-реляционного отображения, без первоначальных представления какую стратегию (или стратегии) кэширования он использует. Существуют три основных типа КЭШа:
• Транзакционный – связанный с текущей единицей работы, которая может быть фактическая транзакция БД или транзакция приложения. Она корректна и используется во время работы единицы работы. Каждая единица работы имеет свой кэш.
• Процессный – распределяется между многими (возможно одновременными) единицами работы или транзакции. Это означает, что данные в процессном КЭШе доступны одновременно выполняемым операциям, очевидно с последствиями для изоляции транзакций. Процессный кэш может хранить хранимые объекты целиком в КЭШе, или может хранить их состояние в разобранном формате.
• Кластерный – распределяется между несколькими процессами на одной машине или между несколькими машинами в кластере. Он требует какой-то удаленный процесс взаимодействия для поддержания согласованности. Кэширование информации должно быть продублировано на всех узлах кластера. Для многих (не всех) приложений, кластерное кэширование имеет сомнительную ценность, так как чтение и обновление КЭШа может быть лишь незначительно быстрее, чем прямое обращение в БД.
Хранимые слои могут обеспечивать несколько уровней кэширования. Например, промах КЭШа(cache miss) (поиск элемента в КЭШе, который там не содержится) в транзакционном типе может последовать за поиском в процессном. Запрос к БД будет последней инстанцией.
Тип КЭШа, используемый хранимым уровнем, влияет на сферу идентичности объектов (взаимосвязь между Java идентичностью и идентичностью на уровне БД)