Advanced HibernateHibernate in a Nutshell A solid product, widely used Use a mapping layer to map...
Transcript of Advanced HibernateHibernate in a Nutshell A solid product, widely used Use a mapping layer to map...
Hosted by Tikal. w w w . t i k a l k . c o m Cost-Benefit Open Source
Advanced Hibernate Advanced Hibernate
Israel JBoss User GroupIsrael JBoss User GroupSession 02 / 5.6.2006Session 02 / 5.6.2006
By : Yanai Franchi, Senior Software Engineer By : Yanai Franchi, Senior Software Engineer “Tikal” “Tikal”
Hosted by Tikal | 2 | www.tikalk.com
Israe
l JBU
G
AgendaAgenda
Overview and RecapOverview and Recap Advanced MappingsAdvanced Mappings Transactional ProcessingTransactional Processing Querying and FetchingQuerying and Fetching TuningTuning
Hosted by Tikal | 3 | www.tikalk.com
Israe
l JBU
G
Overview and RecapOverview and Recap
Hosted by Tikal | 4 | www.tikalk.com
Israe
l JBU
G
The Core ProblemThe Core Problem
!= The Object-Relational impedance mismatch» How do we map tables and column to objects
Getting persistence right is essential» Failure in persistency strategy will make any non-trivial
application fail
Hosted by Tikal | 5 | www.tikalk.com
Israe
l JBU
G
Hibernate in a NutshellHibernate in a Nutshell A solid product, widely used Use a mapping layer to map between objects and
tables» XML» Annotations
Dual-Layer Caching Architecture (HDLCA) Powerful, high performance queries Support for detached objects (no DTOs) …and many more cool features Provide a great programming model » Non invasive » Transparent and transitive
Hosted by Tikal | 6 | www.tikalk.com
Israe
l JBU
G
Three Ways to Achieve Persistency…Three Ways to Achieve Persistency…
hibernate.cfghbm files
Hibernate API
Hosted by Tikal | 7 | www.tikalk.com
Israe
l JBU
G
Hibernate MappingHibernate Mapping
package com.tikal.sample;public class User {
private Long id;private String name;
public User(){}public User(name){
this.name=name;}public void setName(String name) {
this.name = name;}public String getName() {
return name;}
}
Hosted by Tikal | 8 | www.tikalk.com
Israe
l JBU
G
Hibernate Mapping – Cont’Hibernate Mapping – Cont’<hibernate-mapping package="com.tikal.sample">
<class name="User" table="USERS">
<id>...</id>
<property name="name" />
</hibernate-mapping>
<hibernate-configuration>
<session-factory> <property name="dialect"> org.hibernate.dialect.HSQLDialect</property> <property name="connection.driver_class"> org.hsqldb.jdbcDriver </property> <property name="connection.url"> jdbc:hsqldb:mem:aname </property> <property name="connection.username">sa</property> <property name="connection.password"></property>
<mapping resource=“model/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
User.hbm
Hibernate.cfg
Hosted by Tikal | 9 | www.tikalk.com
Israe
l JBU
G
Hibernate API ExampleHibernate API ExampleSessionFactory sf =
new Configuration().buildSessionFactory();
Session s = sf.openSession();Transaction t = s.beginTransaction();
u = new User("Yossi");s.save(u);
t.commit();s.close();
sf.close();
insert into users (id, name) values (1,’Yossi’)
Hosted by Tikal | 10 | www.tikalk.com
Israe
l JBU
G
Three Ways to Achieve Persistency…Three Ways to Achieve Persistency…
hibernate.cfghbm files
Hibernate API
persistence.xmlEJB3 Annotations
JPA
Hosted by Tikal | 11 | www.tikalk.com
Israe
l JBU
G
What is JPA ?What is JPA ? Java Persistence API is now the standard API
for ORM for the Java EE platform. » Simplifies the development of JEE and JSE
applications using data persistence.» Get the entire Java community behind a single,
standard persistence API Originated as an improvement of EJB-CMP
and became a separate persistence spec for POJOs.
Usable both within JSE5 and JEE5 We can use Hibernate (or other ORM
implementation) as the persistence provider.
Hosted by Tikal | 12 | www.tikalk.com
Israe
l JBU
G
JPA MappingJPA Mappingimport javax.persistence.*;package com.tikal.sample;
@Entity @Table(name=“USERS") public class User{
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;private String name;User(){}public User(name){
this.name=name;}public void setName(String name) {
this.name = name;}public String getName() {
return name;}
}
Hosted by Tikal | 13 | www.tikalk.com
Israe
l JBU
G
JPA Configuration - persistence.xmlJPA Configuration - persistence.xml<persistence> <persistence-unit name="manager1“
transaction-type=“RESOURCE_LOCAL”> <class>com.tikal.sample.User</class>
<properties> <property name="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.connection.driver_class"
value="org.hsqldb.jdbcDriver" /> <property name="hibernate.connection.url"
value="jdbc:hsqldb:mem:aname" /> <property name="hibernate.connection.username" value="sa" /> <property name="hibernate.connection.password" value="" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <property name="hibernate.cache.provider_class"
value="org.hibernate.cache.NoCacheProvider" /> </properties> </persistence-unit></persistence>
Hosted by Tikal | 14 | www.tikalk.com
Israe
l JBU
G
JPA in ActionJPA in Action EntityManagerFactory emf = Persistence
.createEntityManagerFactory("manager1"); EntityManager em = emf.createEntityManager();
User u = new User(“Yossi”);
em.persist(u); User u2 = (User)em.find(User.class,u.getId());
List<User> users = em.createQuery ("from User as u where u.name = :name")
.setParameter(“name",”Yossi”) .getResultList(); em.close(); emf.close();
Hosted by Tikal | 15 | www.tikalk.com
Israe
l JBU
G
Three Ways to Achieve Persistency…Three Ways to Achieve Persistency…
hibernate.cfghbm files
Hibernate API
persistence.xmlEJB3 Annotations
JPA API
hibernate.cfgEJB3+Hibernate+Validation
Hosted by Tikal | 16 | www.tikalk.com
Israe
l JBU
G
Hibernate AnnotationsHibernate Annotationsimport javax.persistence.*;@Entity @Table(name=“USERS") @org.hibernate.annotations.Entity(mutable=false)public class User{
@Id@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;private String name;User(){}public User(name){
this.name=name;}public void setName(String name) {
this.name = name;}
@org.hibernate.validator.Length(max=8) @org.hibernate.validator.NotNull
public String getName() {return name;
}}
Hosted by Tikal | 17 | www.tikalk.com
Israe
l JBU
G
Hibernate Annotations Cont.Hibernate Annotations Cont.<hibernate-configuration> <session-factory>
… <mapping class="com.tikal.sample.User"/> </session-factory></hibernate-configuration>
SessionFactory sf = new AnnotationConfiguration().buildSessionFactory();
Session s = sf.openSession();Transaction t = s.beginTransaction();
u = new User("Yossi");s.save(u); //hibernate apis.persist(u); // Java Persistent api
t.commit();s.close();
sf.close();
Hosted by Tikal | 18 | www.tikalk.com
Israe
l JBU
G
Dynamic ModelsDynamic Models
Dynamic Models» Map of Maps» Dom4j trees» Implement your own Tuplizer
Change The default entity model
pojoSession.getSession(EntityMode.MAP);
hibernate.default_entity_mode=dynamic-map
Hosted by Tikal | 19 | www.tikalk.com
Israe
l JBU
G
Dynamic-Model ExampleDynamic-Model Example
<hibernate-mapping> … <class entity-name="Customer"> <id name="id" type="long" column="ID"> <generator class="sequence"/> </id> <property name=“firstName" column=“FIRST_NAME"/> <property name=“lastName" column=“LAST_NAME"/> <many-to-one name=“relatedOrganization”
cascade=“save-update“ class="Organization"/> </class></hibernate-mapping>
Customer Organizationn 1
Hosted by Tikal | 20 | www.tikalk.com
Israe
l JBU
G
Dynamic Model Example Cont.Dynamic Model Example Cont.Session s = openSession();Transaction tx = s.beginTransaction();
Map myOrganzation = new HashMap();myOrganzation.put("name", “Foo inc");
Map myCustomer = new HashMap();myCustomer.put(“firstName", "David");myCustomer.put(“lastName", “Mor");myCustomer.put("relatedOrganization", myOrganzation);
s.save("Customer", myCustomer);
tx.commit();s.close();
Hosted by Tikal | 21 | www.tikalk.com
Israe
l JBU
G
Transactional Transactional ProcessingProcessing
Hosted by Tikal | 22 | www.tikalk.com
Israe
l JBU
G
The Persistence LifecycleThe Persistence Lifecycle
Hosted by Tikal | 23 | www.tikalk.com
Israe
l JBU
G
Persistence by Reachability Persistence by Reachability An Object becomes persistence if it is referenced
from a persistent instance
Categoryn
1
addCategories
Hosted by Tikal | 24 | www.tikalk.com
Israe
l JBU
G
Transitivity Persistence ExampleTransitivity Persistence Example
// Creating Transient categories
Category monitors = new Category(“monitors”); Category desktopPCs = new Category(“desktopPCs”);
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Category computers = (Category)session.get(Category.class,computersId);
computers.addCategory(monitors); //-> Persistent
computers.addCategory(desktopPCs); //-> Persistent
tx.commit();
session.close();
Hosted by Tikal | 25 | www.tikalk.com
Israe
l JBU
G
Identity ProblemIdentity Problem Java objects define two different notions of
sameness:» Object identity (a == b)» equality by value ( equals() method )
The identity of a database row is expressed as the primary key value.
Hosted by Tikal | 26 | www.tikalk.com
Israe
l JBU
G
Which Scope does Hibernate Which Scope does Hibernate Implement?Implement?
Session session1 = sessions.openSession();Transaction tx1 = session1.beginTransaction();Object a = session1.load(User.class, new Long(1234));Object b = session1.load(User.class, new Long(1234));System.out.println(a==b);//trueSystem.out.println(a.equals(b)); // truetx1.commit();session1.close();
Session session2 = sessions.openSession();Transaction tx2 = session2.beginTransaction();Object b2 = session2.load(User.class, new Long(1234));System.out.println(a==b2);//falseSystem.out.println(a.equals(b2)); //falsetx2.commit();session2.close();
Hosted by Tikal | 27 | www.tikalk.com
Israe
l JBU
G
Primary KeyPrimary Keypublic class User {
...public boolean equals(Object other) {
if (this==other) return true;if (id==null) return false;if ( !(other instanceof User) ) return false;
final User that = (User) other;return this.id.equals( that.getId() );
}
public int hashCode() {return (id==null) ?
System.identityHashCode(this) :id.hashCode();
}}
Might break java.util.Set contract!
Hosted by Tikal | 28 | www.tikalk.com
Israe
l JBU
G
Business KeyBusiness Keypublic class User {
...public boolean equals(Object other) {
if (this==other) return true;if ( !(other instanceof User) ) return false;final User that = (User) other;return this.name.equals( that.getName() );
}public int hashCode() {
return name.hashCode();}
}
Identify the business key
Hosted by Tikal | 29 | www.tikalk.com
Israe
l JBU
G
Querying and FetchingQuerying and Fetching
Hosted by Tikal | 30 | www.tikalk.com
Israe
l JBU
G
The n+1 Selects ProblemThe n+1 Selects Problem
Suppose we wanted initialize items collection of each category:
List<Category> categories = session.createQuery("from Category“).list();
for (Category category : categories) {for (Item item :category.getItems()) {
if(item.getPrice >123) //doSomething}
}
Category Item1 n
Hosted by Tikal | 31 | www.tikalk.com
Israe
l JBU
G
Eager FetchingEager Fetching
Keep everything lazy and use runtime fetching:List<Category> categoris =
new HashSet(session.createQuery("from Category c fetch join c.items“).list());
for (Category category : categories) {for (Item item :category.getItems()) {
if(item.getPrice >123) //doSomething}
}
Hosted by Tikal | 32 | www.tikalk.com
Israe
l JBU
G
Caching Scope Caching Scope
Suppose we want to display the category tree frequently
Categoryn
1
Category root = openSession().createQuery("from Category c fetch join c.categories
where c.name =:root“).setString(“root”,”Root”).uniqueResult();
displayCategoryTree(root);closeSession();
Hosted by Tikal | 33 | www.tikalk.com
Israe
l JBU
G
Caching Scope – Cont’Caching Scope – Cont’
On a Tree of n categories, this code will still have O(n) selects!
We must use the 2nd level cache here…
void displayCategoryTree(Category c){ display(c); for (Category child : c.getChildren()) {
displayCategoryTree (child);}
}
Hosted by Tikal | 34 | www.tikalk.com
Israe
l JBU
G
Hibernate Cache Architecture Hibernate Cache Architecture
Hosted by Tikal | 35 | www.tikalk.com
Israe
l JBU
G
Using the 2Using the 2ndnd level Cache level Cache<hibernate-configuration> <session-factory> ... <property name="cache.provider_class"> net.sf.ehcache.hibernate.EhCacheProvider </property> <property name="cache.use_query_cache">
true </property> ... <class-cache class="com.myapp.Category“
usage="read-write"/> <collection-cache
collection="com.myapp.Category.children" usage="read-write"/>
</session-factory></hibernate-configuration>
Category root = openSession().createQuery("from Category c where c.name =:root“)
.setString(“root”,”Root”)
.setCacheable(true).uniqueResult();displayCategoryTree(root);closeSession();
Hosted by Tikal | 36 | www.tikalk.com
Israe
l JBU
G
Batch Processing ProblemBatch Processing ProblemSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction();
List<Customer> customers =session.getNamedQuery( "GetCustomers").list()
for (Customer customer : customers)customer.updateStuff(...);
tx.commit();session.close();
Fail with an OutOfMemoryError somewhere around the 50,000th row
Hosted by Tikal | 37 | www.tikalk.com
Israe
l JBU
G
Batch Processing ExampleBatch Processing ExampleSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers").setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
int count=0;while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);customer.updateStuff(...);if ( ++count % 20 == 0 ) {
// flush a batch of updates and release memorysession.flush();session.clear();
}}tx.commit();session.close();
Hosted by Tikal | 38 | www.tikalk.com
Israe
l JBU
G
StatelessSessionStatelessSession Lower-level abstraction, much closer to the
underlying JDBC. No associated persistence context. Does not implement a first-level cache nor interact
with any second-level or query cache. Does not implement transactional write-behind or
automatic dirty checking. Operations do not ever cascade to associated
instances. Collections are ignored by a stateless session. Bypass Hibernate's event model and interceptors. insert(), update() and delete() have different
semantics than save(), saveOrUpdate() and delete()
Hosted by Tikal | 39 | www.tikalk.com
Israe
l JBU
G
StatelessSession ExampleStatelessSession Example
StatelessSession session = sessionFactory.openStatelessSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session
.getNamedQuery("GetCustomers")
.scroll(ScrollMode.FORWARD_ONLY);
while (customers.next()) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
session.update(customer);
}
tx.commit();
session.close();
Hosted by Tikal | 40 | www.tikalk.com
Israe
l JBU
G
DML-Style OperationsDML-Style Operations
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate ).setString( "newName", newName ).setString( "oldName", oldName ).executeUpdate();
tx.commit();
session.close();
Hosted by Tikal | 41 | www.tikalk.com
Israe
l JBU
G
Filtering DataFiltering Data
<filter-def name="effectiveDate"> <filter-param name="asOfDate" type="date"/></filter-def>
<class name="Employee" ...> ... <property name=“userName”/> <property name="effectiveStartDate"/> <property name="effectiveEndDate"/> ... <filter name="effectiveDate“ condition=":asOfDate BETWEEN
effectiveStartDate and effectiveEndDate "/></class>
Hosted by Tikal | 42 | www.tikalk.com
Israe
l JBU
G
Filtering in ActionFiltering in Action
Session session = ...; session.enabledFilter("effectiveDate") .setParameter ("asOfDate", new Date()); List results = session.createQuery(
"from Employee as e where e.salary > :targetSalary").setLong("targetSalary", new Long(1000000)).list();
Return the currently working employees with salary above 1,000,000
Hosted by Tikal | 43 | www.tikalk.com
Israe
l JBU
G
Q&AQ&A