Israel JBoss User Group
Session 02 / 5.6.2006
Advanced Hibernate
By : Yanai Franchi, Senior Software Engineer “Tikal”
Hosted by Tikal. [Link] Cost-Benefit Open Source
Israel JBUG
Agenda
Overview and Recap
Advanced Mappings
Transactional Processing
Querying and Fetching
Tuning
Hosted by Tikal | 2 | [Link]
Israel JBUG
Overview and Recap
Hosted by Tikal | 3 | [Link]
Israel JBUG
The 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 | 4 | [Link]
Israel JBUG
Hibernate 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 | 5 | [Link]
Israel JBUG
Three Ways to Achieve Persistency…
Hibernate API
[Link]
hbm files
Hosted by Tikal | 6 | [Link]
Israel JBUG
Hibernate Mapping
package [Link];
public class User {
private Long id;
private String name;
public User(){}
public User(name){
[Link]=name;
}
public void setName(String name) {
[Link] = name;
}
public String getName() {
return name;
}
}
Hosted by Tikal | 7 | [Link]
Israel JBUG
Hibernate Mapping – Cont’
<hibernate-mapping package="[Link]"> [Link]
<class name="User" table="USERS">
<id>...</id>
<property name="name" />
</hibernate-mapping>
<hibernate-configuration> [Link]
<session-factory>
<property name="dialect">
[Link]</property>
<property name="connection.driver_class">
[Link]
</property>
<property name="[Link]">
jdbc:hsqldb:mem:aname
</property>
<property name="[Link]">sa</property>
<property name="[Link]"></property>
<mapping resource=“model/[Link]"/>
</session-factory>
</hibernate-configuration>
Hosted by Tikal | 8 | [Link]
Israel JBUG
Hibernate API Example
SessionFactory sf =
new Configuration().buildSessionFactory();
Session s = [Link]();
Transaction t = [Link]();
u = new User("Yossi");
[Link](u);
[Link]();
[Link]();
[Link]();
insert into users (id, name) values (1,’Yossi’)
Hosted by Tikal | 9 | [Link]
Israel JBUG
Three Ways to Achieve Persistency…
JPA Hibernate API
[Link] [Link]
EJB3 Annotations hbm files
Hosted by Tikal | 10 | [Link]
Israel JBUG
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 | 11 | [Link]
Israel JBUG
JPA Mapping
import [Link].*;
package [Link];
@Entity @Table(name=“USERS")
public class User{
@Id
@GeneratedValue(strategy = [Link])
private Long id;
private String name;
User(){}
public User(name){
[Link]=name;
}
public void setName(String name) {
[Link] = name;
}
public String getName() {
return name;
}
}
Hosted by Tikal | 12 | [Link]
Israel JBUG
JPA Configuration - [Link]
<persistence>
<persistence-unit name="manager1“
transaction-type=“RESOURCE_LOCAL”>
<class>[Link]</class>
<properties>
<property name="[Link]"
value="[Link]" />
<property name="[Link].driver_class"
value="[Link]" />
<property name="[Link]"
value="jdbc:hsqldb:mem:aname" />
<property name="[Link]" value="sa" />
<property name="[Link]" value="" />
<property name="hibernate.show_sql" value="true" />
<property name="[Link]" value="create-drop" />
<property name="[Link].provider_class"
value="[Link]" />
</properties>
</persistence-unit>
</persistence>
Hosted by Tikal | 13 | [Link]
Israel JBUG
JPA in Action
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("manager1");
EntityManager em = [Link]();
User u = new User(“Yossi”);
[Link](u);
User u2 = (User)[Link]([Link],[Link]());
List<User> users = [Link]
("from User as u where [Link] = :name")
.setParameter(“name",”Yossi”)
.getResultList();
[Link]();
[Link]();
Hosted by Tikal | 14 | [Link]
Israel JBUG
Three Ways to Achieve Persistency…
JPA API Hibernate API
[Link] [Link]
EJB3 Annotations hbm files
[Link]
EJB3+Hibernate+Validation
Hosted by Tikal | 15 | [Link]
Israel JBUG
Hibernate Annotations
import [Link].*;
@Entity @Table(name=“USERS")
@[Link](mutable=false)
public class User{
@Id
@GeneratedValue(strategy = [Link])
private Long id;
private String name;
User(){}
public User(name){
[Link]=name;
}
public void setName(String name) {
[Link] = name;
}
@[Link](max=8)
@[Link]
public String getName() {
return name;
}
}
Hosted by Tikal | 16 | [Link]
Israel JBUG
Hibernate Annotations Cont.
<hibernate-configuration>
<session-factory>
…
<mapping class="[Link]"/>
</session-factory>
</hibernate-configuration>
SessionFactory sf =
new AnnotationConfiguration().buildSessionFactory();
Session s = [Link]();
Transaction t = [Link]();
u = new User("Yossi");
[Link](u); //hibernate api
[Link](u); // Java Persistent api
[Link]();
[Link]();
[Link]();
Hosted by Tikal | 17 | [Link]
Israel JBUG
Dynamic Models
Dynamic Models
» Map of Maps
» Dom4j trees
» Implement your own Tuplizer
Change The default entity model
hibernate.default_entity_mode=dynamic-map
[Link]([Link]);
Hosted by Tikal | 18 | [Link]
Israel JBUG
Dynamic-Model Example
n 1
Customer Organization
<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>
Hosted by Tikal | 19 | [Link]
Israel JBUG
Dynamic Model Example Cont.
Session s = openSession();
Transaction tx = [Link]();
Map myOrganzation = new HashMap();
[Link]("name", “Foo inc");
Map myCustomer = new HashMap();
[Link](“firstName", "David");
[Link](“lastName", “Mor");
[Link]("relatedOrganization", myOrganzation);
[Link]("Customer", myCustomer);
[Link]();
[Link]();
Hosted by Tikal | 20 | [Link]
Israel JBUG
Transactional
Processing
Hosted by Tikal | 21 | [Link]
Israel JBUG
The Persistence Lifecycle
Hosted by Tikal | 22 | [Link]
Israel JBUG
Persistence by Reachability
An Object becomes persistence if it is referenced
from a persistent instance 1
n
Category
addCategories
Hosted by Tikal | 23 | [Link]
Israel JBUG
Transitivity Persistence Example
// Creating Transient categories
Category monitors = new Category(“monitors”);
Category desktopPCs = new Category(“desktopPCs”);
Session session = [Link]();
Transaction tx = [Link]();
Category computers =
(Category)[Link]([Link],computersId);
[Link](monitors); //-> Persistent
[Link](desktopPCs); //-> Persistent
[Link]();
[Link]();
Hosted by Tikal | 24 | [Link]
Israel JBUG
Identity 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 | 25 | [Link]
Israel JBUG
Which Scope does Hibernate
Implement?
Session session1 = [Link]();
Transaction tx1 = [Link]();
Object a = [Link]([Link], new Long(1234));
Object b = [Link]([Link], new Long(1234));
[Link](a==b);//true
[Link]([Link](b)); // true
[Link]();
[Link]();
Session session2 = [Link]();
Transaction tx2 = [Link]();
Object b2 = [Link]([Link], new Long(1234));
[Link](a==b2);//false
[Link]([Link](b2)); //false
[Link]();
[Link]();
Hosted by Tikal | 26 | [Link]
Israel JBUG
Primary Key
public 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 [Link]( [Link]() );
}
public int hashCode() {
return (id==null) ?
[Link](this) :
[Link]();
}
}
Might break [Link] contract!
Hosted by Tikal | 27 | [Link]
Israel JBUG
Business Key
public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return [Link]( [Link]() );
}
public int hashCode() {
return [Link]();
}
}
Identify the business key
Hosted by Tikal | 28 | [Link]
Israel JBUG
Querying and Fetching
Hosted by Tikal | 29 | [Link]
Israel JBUG
The n+1 Selects Problem
1 n
Category Item
Suppose we wanted initialize items collection of each category:
List<Category> categories =
[Link]("from Category“).list();
for (Category category : categories) {
for (Item item :[Link]()) {
if([Link] >123) //doSomething
}
}
Hosted by Tikal | 30 | [Link]
Israel JBUG
Eager Fetching
Keep everything lazy and use runtime fetching:
List<Category> categoris =
new HashSet([Link](
"from Category c fetch join [Link]“).list());
for (Category category : categories) {
for (Item item :[Link]()) {
if([Link] >123) //doSomething
}
}
Hosted by Tikal | 31 | [Link]
Israel JBUG
Caching Scope
1
n
Category
Suppose we want to display the category tree
frequently
Category root = openSession().createQuery(
"from Category c fetch join [Link]
where [Link] =:root“)
.setString(“root”,”Root”)
.uniqueResult();
displayCategoryTree(root);
closeSession();
Hosted by Tikal | 32 | [Link]
Israel JBUG
Caching Scope – Cont’
void displayCategoryTree(Category c){
display(c);
for (Category child : [Link]()) {
displayCategoryTree (child);
}
}
On a Tree of n categories, this code will still have
O(n) selects!
We must use the 2nd level cache here…
Hosted by Tikal | 33 | [Link]
Israel JBUG
Hibernate Cache Architecture
Hosted by Tikal | 34 | [Link]
Israel JBUG
Using the 2nd level Cache
<hibernate-configuration>
<session-factory>
...
<property name="cache.provider_class">
[Link]
</property>
<property name="cache.use_query_cache">
true
</property>
...
<class-cache class="[Link]“
usage="read-write"/>
<collection-cache
collection="[Link]"
usage="read-write"/>
</session-factory>
</hibernate-configuration>
Category root = openSession().createQuery(
"from Category c where [Link] =:root“)
.setString(“root”,”Root”)
.setCacheable(true).uniqueResult();
displayCategoryTree(root);
closeSession();
Hosted by Tikal | 35 | [Link]
Israel JBUG
Batch Processing Problem
Session session = [Link]();
Transaction tx = [Link]();
List<Customer> customers =
[Link]( "GetCustomers").list()
for (Customer customer : customers)
[Link](...);
[Link]();
[Link]();
Fail with an OutOfMemoryError
somewhere around the 50,000th row
Hosted by Tikal | 36 | [Link]
Israel JBUG
Batch Processing Example
Session session = [Link]();
Transaction tx = [Link]();
ScrollableResults customers = session
.getNamedQuery("GetCustomers")
.setCacheMode([Link])
.scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( [Link]() ) {
Customer customer = (Customer) [Link](0);
[Link](...);
if ( ++count % 20 == 0 ) {
// flush a batch of updates and release memory
[Link]();
[Link]();
}
}
[Link]();
[Link]();
Hosted by Tikal | 37 | [Link]
Israel JBUG
StatelessSession
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 | 38 | [Link]
Israel JBUG
StatelessSession Example
StatelessSession session =
[Link]();
Transaction tx = [Link]();
ScrollableResults customers = session
.getNamedQuery("GetCustomers")
.scroll(ScrollMode.FORWARD_ONLY);
while ([Link]()) {
Customer customer = (Customer) [Link](0);
[Link](...);
[Link](customer);
}
[Link]();
[Link]();
Hosted by Tikal | 39 | [Link]
Israel JBUG
DML-Style Operations
Session session = [Link]();
Transaction tx = [Link]();
String hqlUpdate = "update Customer c set [Link] =
:newName where [Link] = :oldName";
int updatedEntities = [Link]( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
[Link]();
[Link]();
Hosted by Tikal | 40 | [Link]
Israel JBUG
Filtering 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 | 41 | [Link]
Israel JBUG
Filtering in Action
Session session = ...;
[Link]("effectiveDate")
.setParameter ("asOfDate", new Date());
List results = [Link](
"from Employee as e where [Link] > :targetSalary")
.setLong("targetSalary", new Long(1000000))
.list();
Return the currently working employees with
salary above 1,000,000
Hosted by Tikal | 42 | [Link]
Israel JBUG
Q&A
Hosted by Tikal | 43 | [Link]
Israel JBUG
Thank You
yanai@[Link]
Hosted by Tikal | 44 | [Link]