diff options
author | elmot <elmot@vaadin.com> | 2015-09-25 16:40:44 +0300 |
---|---|---|
committer | elmot <elmot@vaadin.com> | 2015-09-25 16:40:44 +0300 |
commit | a1b265c318dbda4a213cec930785b81e4c0f7d2b (patch) | |
tree | b149daf5a4f50b4f6446c906047cf86495fe0433 /documentation/jpacontainer/jpacontainer-hibernate.asciidoc | |
parent | b9743a48a1bd0394f19c54ee938c6395a80f3cd8 (diff) | |
download | vaadin-framework-a1b265c318dbda4a213cec930785b81e4c0f7d2b.tar.gz vaadin-framework-a1b265c318dbda4a213cec930785b81e4c0f7d2b.zip |
Framework documentation IN
Change-Id: I767477c1fc3745f9e1f58075fe30c9ac8da63581
Diffstat (limited to 'documentation/jpacontainer/jpacontainer-hibernate.asciidoc')
-rw-r--r-- | documentation/jpacontainer/jpacontainer-hibernate.asciidoc | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/documentation/jpacontainer/jpacontainer-hibernate.asciidoc b/documentation/jpacontainer/jpacontainer-hibernate.asciidoc new file mode 100644 index 0000000000..de7f26d9a0 --- /dev/null +++ b/documentation/jpacontainer/jpacontainer-hibernate.asciidoc @@ -0,0 +1,180 @@ +--- +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)) +---- + + + + |