Professional Documents
Culture Documents
Spring + JPA + Hibernate: Lennard Fuller
Spring + JPA + Hibernate: Lennard Fuller
Lennard Fuller
Jasig Conference, 2009
© Copyright Unicon, Inc., 2009. This work is the intellectual property of Unicon, Inc. Permission is granted for this material to be shared for
non-commercial, educational purposes, provided that this copyright statement appears on the reproduced materials and notice is given that
the copying is by permission of Unicon, Inc. To disseminate otherwise or to republish requires written permission from Unicon, Inc.
1. A brief overview of JPA
2. Native Hibernate vs JPA
Vocabulary
3. Improper Interception
4. Inefficient Retrieval
5. equals() & hashcode()
6. QL Injection
7. Caching Concerns
8. Questions?
What is JPA?
JPA: Java Persistence API
Foo Bar
+getBars() 1 * +getFoo()
Simple Example
Foo.java
@Entity
public class Foo {
…
@OneToMany(mappedBy=“foo”)
public Set getBars() { return bars; }
…
}
Bar.java
@Entity
public class Bar {
…
@ManyToOne @JoinColumn(name=“FOO_ID", nullable=false)
public Foo getFoo() { return foo; }
…
}
Simple Example: DAO
@Transactional
public class FooDAO implements IFooDAO{
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
persistenceContext.xml
…
<tx:annotation-driven />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanP
ostProcessor" />
…
Simple Example
1 : query()
Performance Killer
2 : getBars()
X Session per operation anti
Exception!!!! pattern.
Failed to lazily
initialize......., no session JPA
or session was closed
Interception
Remove Example
1 : query()
2 : remove()
X
Exception!!!!
java.lang.IllegalArgument
Exception: Removing a JPA
detached instance ...
Interception
Unecessary Merge
@Transactional
public class FooDAO implements IFooDAO{
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
Performance Killer!!
}
Forces another lookup and
public List query(String queryString, final Object... params) {
… a deep merge with what is
}
in DB. Not necessary
public void removeFoo(Foo foo) {
this.entityManager.remove(this.entityManager.merge(foo));
}
}
Transactional Proxies in Spring
JPA Interception in Spring
1 : query()
Ensure your interception
is at the proper level. Typically,
2 : remove()
at the request, service or
controller layer.
JPA Interception
Means of interception
Using @Transactional
SomeService.java
@Transactional
public class SomeService {
…
}
persistenceContext.xml
…
<tx:annotation-driven />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanP
ostProcessor" />
…
Using Filter: web.xml
…
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-
class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFil
ter</filter-class>
</filter>
…
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
…
JPA Interceptor: persistenceContext.xml
…
<bean id="jpaInterceptor"
class="org.springframework.orm.jpa.JpaInterceptor">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
…
JPA Interceptor: foo_portlet_beans.xml
…
<bean id=“fooPortletBean"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean=“fooPortletBeanTarget"/>
</property>
<property name="proxyInterfaces">
<value>javax.portlet.Portlet</value>
</property>
<property name="interceptorNames">
<list>
<value>jpaInterceptor</value>
</list>
</property>
…
Inefficient Retrieval: N+1
and Cartesian Products
Enemies of performance
• N+1
– Natural result of default lazy behavior
Foo Bar
+getBars() 1 * +getFoo()
N+1
If I use the following JPA QL to render a result for single foo associated to
1000 bars:
Hibernate will have to make 1001 sql queries in order for the data to be
displayed IF the relationship between foo and associated bars is lazy.
from Foo f left join fetch f.bars where f.desciption like ‘%Foo%’
Adding the left join fetch overrides the default lazy relationship and allows
hibernate to retrieve all the data in one sql call.
WARNING: left join fetch is NOT a silver bullet, RTM and then use.
Cartesian Product
• Avoidance:
– Know your data model, only eager fetch when
necessary.
– Never ever fetch parallel collections
How will I know?
Lennard Fuller
lfuller@unicon.net
www.unicon.net