123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- ---
- title: Using JPAContainer with Hibernate
- order: 9
- layout: page
- ---
-
- [[jpacontainer.hibernate]]
- = Using JPAContainer with Hibernate
-
- Hibernate needs special handling in some cases.
-
- [[jpacontainer.hibernate.lazyloading]]
- == Lazy loading
-
- In order for lazy loading to work automatically, an entity must be attached to
- an entity manager. Unfortunately, Hibernate can not keep entity managers for
- long without problems. To work around the problem, you need to use a special
- lazy loading delegate for Hibernate.
-
- JPAContainer entity providers handle lazy loading in delegates defined by the
- [interfacename]#LazyLoadingDelegate# interface. The default implementation for
- Hibernate is defined in [classname]#HibernateLazyLoadingDelegate#. You can
- instantiate one and use it in an entity provider with
- [methodname]#setLazyLoadingDelegate()#.
-
- The default implementation works so that whenever a lazy property is accessed
- through the Vaadin Property interface, the value is retrieved with a separate
- (JPA Criteria API) query using the currently active entity manager. The value is
- then manually attached to the entity instance, which is detached from the entity
- manager. If this default implementation is not good enough, you may need to make
- your own implementation.
-
-
- ifdef::web[]
- [[jpacontainer.hibernate.em-per-request]]
- == The EntityManager-Per-Request pattern
-
- One issue with Hibernate is that it is designed for short-lived sessions, but
- the lifetime of an entity manager is normally roughly that of a user session.
- The problem is that if an error occurs in a session or an entity manager, the
- manager becomes unuseable. This causes big problems with long-lived sessions
- that would work fine with EclipseLink.
-
- The recommended solution is to use the __EntityManager-per-Request__ pattern. It
- is highly recommended always when using Hibernate.
-
- An entity manager can only be open during the request-response cycle of the
- Vaadin servlet, so that one is created at the beginning of the request and
- closed at the end.
-
- [[jpacontainer.hibernate.em-per-request.provider]]
- === Storing an Entity Manager
-
- You first need to implement an [interfacename]#EntityManagerProvider# that
- returns a stored [interfacename]#EntityManager# with
- [methodname]#getEntityManager()#. The entity manager must be stored in a
- [classname]#ThreadLocal# variable.
-
-
- ----
- public class LazyHibernateEntityManagerProvider
- implements EntityManagerProvider {
- private static ThreadLocal<EntityManager>
- entityManagerThreadLocal =
- new ThreadLocal<EntityManager>();
-
- @Override
- public EntityManager getEntityManager() {
- return entityManagerThreadLocal.get();
- }
-
- public static void setCurrentEntityManager(
- EntityManager em) {
- entityManagerThreadLocal.set(em);
- }
- }
- ----
-
- You need to create and store the per-request instance at the beginning of each
- request with [methodname]#setCurrentEntityManager()# and clear it at the end by
- setting it as [literal]#++null++#.
-
-
- [[jpacontainer.hibernate.em-per-request.provider]]
- === Creating Entity Managers in a Servlet Filter
-
- You can create the entity managers for each request either by extending
- [classname]#VaadinServlet# and overriding the [methodname]#service()# method or
- by implementing a servlet filter. In the following, we describe how to implement
- a servlet filter to do the task, but overriding the servlet could be even
- easier.
-
-
- ----
- public class LazyHibernateServletFilter
- implements Filter {
-
- private EntityManagerFactory entityManagerFactory;
-
- @Override
- public void init(FilterConfig filterConfig)
- throws ServletException {
- entityManagerFactory = Persistence
- .createEntityManagerFactory("lazyhibernate");
- }
-
- @Override
- public void doFilter(ServletRequest servletRequest,
- ServletResponse servletResponse,
- FilterChain filterChain)
- throws IOException, ServletException {
- try {
- // Create and set the entity manager
- LazyHibernateEntityManagerProvider
- .setCurrentEntityManager(
- entityManagerFactory
- .createEntityManager());
-
- // Handle the request
- filterChain.doFilter(servletRequest,
- servletResponse);
- } finally {
- // Reset the entity manager
- LazyHibernateEntityManagerProvider
- .setCurrentEntityManager(null);
- }
- }
-
- @Override
- public void destroy() {
- entityManagerFactory = null;
- }
- }
- ----
-
- You need to define the servlet filter in the [filename]#web.xml# deployment
- descriptor as follows:
-
- [subs="normal"]
- ----
- <filter>
- <filter-name>**LazyHibernateServletFilter**</filter-name>
- <filter-class>**com.example.LazyHibernateServletFilter**</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>**LazyHibernateServletFilter**</filter-name>
- <url-pattern>**/++*++**</url-pattern>
- </filter-mapping>
- ----
- The [literal]#++url-pattern++# must match the pattern for your Vaadin servlet.
-
-
- endif::web[]
-
- [[jpacontainer.hibernate.joins]]
- == Joins in Hibernate vs EclipseLink
-
- EclipseLink supports implicit joins, while Hibernate requires explicit joins. In
- SQL terms, an explicit join is a " [literal]#++FROM a INNER JOIN b ON a.bid =
- b.id++#" expression, while an implicit join is done in a WHERE clause, such as:
- " [literal]#++FROM a,b WHERE a.bid = b.id++#".
-
- In a JPAContainer filter with EclipseLink, an implicit join would have form:
-
-
- ----
- new Equal("skills.skill", s)
- ----
-
- In Hibernate you would need to use [classname]#JoinFilter# for the explicit
- join:
-
-
- ----
- new JoinFilter("skills", new Equal("skill", s))
- ----
-
-
-
|