April 14, 2005 1Hibernate in 60 Minutes
[ ]Hibernate in 60 Minutes
Eric M. Burke
www.ericburke.com
April 14, 2005 2Hibernate in 60 Minutes
[ ]My JDBC Experience
 Frustration drove me to investigate
Hibernate
 Custom JDBC frameworks and idioms
○ Usually a class called JdbcUtil with static methods
 Custom code generators
○ Database metadata is too cool to resist
 Custom strategy for optimistic locking
 Database-specific ID generation
April 14, 2005 3Hibernate in 60 Minutes
[ ]Typical JDBC Problems
 Massive duplication
 Tied to specific
database
 Error-prone
try/catch/finally
 Relationships are
really hard
○ N+1 selects problem
○ parent/child updates
 delete all then add
 Screen-specific
DAOs for
optimization
April 14, 2005 4Hibernate in 60 Minutes
[ ]Hibernate Questions
 How hard is it to learn and use?
 How invasive is it to my code?
 What are the configuration headaches?
○ Yet another framework with XML files, JAR files,
additional build complexity?
 Does it simplify my life?
April 14, 2005 5Hibernate in 60 Minutes
[ ]What is Hibernate?
 Java Object/Relational Mapping
○ Open source – LGPL
○ http://www.hibernate.org/ (JBoss Group)
 Lets you avoid SQL
 Works with (almost) all relational DBs
○ DB2, FrontBase, HSQLDB, Informix, Ingres, Interbase,
Mckoi, MySQL, Oracle, Pointbase, PostgreSQL, Progress,
SAP DB, SQL Server, Sybase, etc...
○ Or you can extend one of the Dialect classes
April 14, 2005 6Hibernate in 60 Minutes
[ ]What is Hibernate? (Cont'd)
 Has a huge feature list
○ Go to their web site – we don't have time
 Maps JavaBeans (POJOs) to tables
○ XML defines the mappings
○ Very few bean requirements
 SQL is generated at app startup time
○ As opposed to bytecode manipulation
○ New database? No problem! Change a few props
April 14, 2005 7Hibernate in 60 Minutes
[ ]Avoiding SQL
 Hibernate Query Language approach
public User getByScreenName(String screenName) {
try {
return (User) getSession().createQuery(
"from User u where u.screenName=:screenName")
.setString("screenName", screenName)
.uniqueResult();
} catch (HibernateException e) {
throw new DaoException(e);
}
}
 Code-based query API
public User getByScreenName(String screenName) {
return getUnique(Expression.eq("screenName", screenName));
}
JavaBeans
Property Name
April 14, 2005 8Hibernate in 60 Minutes
[ ]Sample Application Code
Session session = getSessionFactory().openSession();
// assume we know the root category id is 1
Category rootCategory = (Category) session.load(
Category.class, new Long(1));
// we can immediately traverse the collection of messages
// without any additional Hibernate code
for (Object msgObj : rootCategory.getMessages()) {
Message msg = (Message) msgObj; // generics+XDoclet==bad
System.out.println(“Subject: “ + msg.getSubject());
System.out.println(“Body: “ + msg.getBody());
System.out.println();
}
session.close();
April 14, 2005 9Hibernate in 60 Minutes
[ ]Sample Code with Transaction
Session sess = ...
Transaction tx = sess.beginTransaction();
// find the root category using Criteria
Criteria criteria = sess.createCriteria(Category.class);
criteria.add(Expression.isNull("parentCategory"));
Category rootCategory = (Category) criteria.uniqueResult();
// change something
rootCategory.setDescription(“The Root Category”);
tx.commit();
sess.close();
April 14, 2005 10Hibernate in 60 Minutes
[ ]Development Options
 Start with the database
○ Use middlegen to generate mapping files
○ Use hbm2java to generate JavaBeans
 Start with JavaBeans
○ Use XDoclet to generate mapping files
○ Use hbm2ddl to generate the database
 Start with the XML mapping files
○ Hand-code the mapping files
○ Use both hbm2java and hbm2ddl
C
April 14, 2005 11Hibernate in 60 Minutes
[ ]Hibernate Tutorial
 Design the database
 Code some persistent classes
 Write an Ant buildfile
○ Generate the mapping files and hibernate.cfg.xml
 Choose a strategy for sessions and
transactions (Spring framework)
 Write and test the DAOs
 Add business logic and helper methods
April 14, 2005 12Hibernate in 60 Minutes
[ ]Database Design
 Design your database first
Categories
PK id
name
description
FK1 parentCategoryId
Resources
PK id
name
url
description
createdOn
CategoriesResources
PK,FK1 categoryId
PK,FK2 resourceId
Surrogate Keys
Work Best
many-to-one
many-to-many
April 14, 2005 13Hibernate in 60 Minutes
[ ]Persistent Objects
 POJOs - Plain Old Java Objects
○ No base class or interface requirement
 Must have public no-arg constructor
 Should have getter/setters
○ Or Hibernate can access fields directly
○ Hibernate uses JavaBeans property names
 For mappings as well as in queries
 Serializable is recommended
 XDoclet tags are useful but not required
April 14, 2005 14Hibernate in 60 Minutes
[ ]My Base Class
public class PersistentClass implements Serializable {
private static final long serialVersionUID = 1;
private Long id;
/**
* @hibernate.id
* column="id"
* unsaved-value="null"
* generator-class="native"
* access="field"
*/
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
}
Hibernate assigns the id
April 14, 2005 15Hibernate in 60 Minutes
[ ]Category Class
public class Category extends NameDescription {
private static final long serialVersionUID = 1;
private Set childCategories = new HashSet();
private Set resources = new HashSet();
private Category parentCategory;
public Category() {
}
public Category(String name, String description) {
super(name, description);
}
public Set getChildCategories() {
return childCategories;
}
public void setChildCategories(Set childCategories) {
this.childCategories = childCategories;
}
My base
class, not
Hibernate's
April 14, 2005 16Hibernate in 60 Minutes
[ ]Category (Cont'd)
public Category getParentCategory() {
return parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public Set getResources() {
return resources;
}
public void setResources(Set resources) {
this.resources = resources;
}
}
April 14, 2005 17Hibernate in 60 Minutes
[ ]Mapping Files
 Generated by XDoclet, 1 per persistent bean
<hibernate-mapping>
<class name="com.ericburke.linkblog.model.Category"
table="Categories">
<id name="id" column="id" type="java.lang.Long"
unsaved-value="null">
<generator class="native"/>
</id>
<set name="childCategories" lazy="true"
inverse="true" cascade="save-update">
<key column="parentCategoryId"/>
<one-to-many class="com.ericburke.linkblog.model.Category"/>
</set>
<many-to-one name="parentCategory"
class="com.ericburke.linkblog.model.Category"
cascade="none" column="parentCategoryId" not-null="false"/>
Or Java 5
Annotations
April 14, 2005 18Hibernate in 60 Minutes
[ ]Mapping Files (Cont'd)
<set name="resources" table="CategoriesResources"
lazy="true" cascade="save-update">
<key column="categoryId"/>
<many-to-many column=”resourceId”
class="com.ericburke.linkblog.model.Resource"/>
</set>
<property name="name" type="java.lang.String"
column="name" length="255"/>
<property name="description" type="java.lang.String"
column="description" length="2000"/>
</class>
</hibernate-mapping>
April 14, 2005 19Hibernate in 60 Minutes
[ ]Xdoclet Tag Example
/**
* @hibernate.class table="Categories"
*/
public class Category extends NameDescription {
/**
* @hibernate.set cascade="save-update" inverse="true"
* lazy="true"
* @hibernate.collection-key column="parentCategoryId"
* @hibernate.collection-one-to-many
* class="com.ericburke.linkblog.model.Category"
*/
public Set getChildCategories() {
return childCategories;
}
// no tags on the setters
public void setChildCategories(Set childCategories) { }
April 14, 2005 20Hibernate in 60 Minutes
[ ]hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="dialect">
net.sf.hibernate.dialect.HSQLDialect</property>
<property name="show_sql">true</property>
<property name="use_outer_join">false</property>
<property name="connection.username">sa</property>
<property name="connection.driver_class">
org.hsqldb.jdbcDriver</property>
<property name="connection.url">
jdbc:hsqldb:hsql://localhost/linkblog</property>
<property name="connection.pool_size">5</property>
<mapping
resource="com/ericburke/linkblog/model/Category.hbm.xml"/>
<mapping
resource="com/ericburke/linkblog/model/Resource.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Generated by XDoclet, or
use Spring's XML file
April 14, 2005 21Hibernate in 60 Minutes
[ ]Ant Buildfile
 Invokes XDoclet
○ XDoclet ships with the Hibernate tasks
○ Generates mapping files and hibernate.cfg.xml
 Hibernate includes tasks for
○ hbm2java – generates the persistent classes
○ hbm2ddl – generates the database
 Classpath needs
○ Hibernate Jars, Hibernate extensions, XDoclet,
JDBC driver JAR file
Requires the persistent
.class files in the
taskdef's classpath
April 14, 2005 22Hibernate in 60 Minutes
[ ]HibernateUtil
 Trivial examples show this class
○ Creates a SessionFactory in the static initializer
Configuration cfg = new Configuration();
SessionFactory sessionFactory =
cfg.configure("/hibernate.cfg.xml")
.buildSessionFactory();
 Provides access to a Session ThreadLocal
public static Session getSession() {
Session s = (Session) threadSession.get();
if (s == null) {
s = sessionFactory.openSession();
threadSession.set(s);
}
return s;
 APIs to begin/commit/rollback transactions
April 14, 2005 23Hibernate in 60 Minutes
[ ]DAOs
 Insulate your code from Hibernate specifics
 CRUD operations
○ I use Java 5 generics heavily
○ You can also use Spring for DAO support
 Locating persistent objects
○ Use Hibernate queries for efficiency
○ From there, walk the graph using normal Java
collections semantics
 Detached objects can be challenging
April 14, 2005 24Hibernate in 60 Minutes
[ ]Servlet Filter
public class HibernateFilter implements Filter {
public void init(FilterConfig fc) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain filterChain)
throws IOException, ServletException {
try {
filterChain.doFilter(req, res);
HibernateUtil.commitTransaction();
} finally {
HibernateUtil.closeSession();
}
}
}
Hibernate in Action,
page 304
April 14, 2005 25Hibernate in 60 Minutes
[ ]Business Objects
 A layer between your application code and
the DAOs
○ Only allow business objects to hit the DAOs
○ Business objects and app code use persistent objects
 Provide a consistent place to use AOP
○ try/catch/finally for transactions
 Risk duplicating DAO code
○ Sometimes business object methods just delegate
April 14, 2005 26Hibernate in 60 Minutes
[ ]Architecture Summary
AOP for
Transactions
Persistent
Objects
Application
Code
DAOs Hibernate Database
XML
Mappings
Business
Objects
Keep an
Open Session
April 14, 2005 27Hibernate in 60 Minutes
[ ]Gotchas
 Must always have an open session
○ Seemingly innocent code like fetching a lazy
collection bombs
○ Swing – open a session on event thread
○ Servlets – use a filter or Spring
 Hibernate tasks do not abort Ant
○ No failonerror attribute
○ Watch the build output carefully
 Test associations and collections heavily
April 14, 2005 28Hibernate in 60 Minutes
[ ]When Not to Use Hibernate
 A horrible database design is forced on you
○ Many composite keys
 If your application is mostly mass
operations
○ See pg. 181 “Hibernate in Action”
○ You might exhaust available heap space
 ??
April 14, 2005 29Hibernate in 60 Minutes
[ ]10 Reasons to Love Hibernate
1.Dynamic UPDATE
generation – figure out
which columns
changed
2.Trying new databases
3.Traversing
associations
4.Optimistic Locking
5.ID generation
6.No more DTOs
7.Query result paging
8.Automatic dirty
checking
9.Good price
10.Good documentation

Hibernate

  • 1.
    April 14, 20051Hibernate in 60 Minutes [ ]Hibernate in 60 Minutes Eric M. Burke www.ericburke.com
  • 2.
    April 14, 20052Hibernate in 60 Minutes [ ]My JDBC Experience  Frustration drove me to investigate Hibernate  Custom JDBC frameworks and idioms ○ Usually a class called JdbcUtil with static methods  Custom code generators ○ Database metadata is too cool to resist  Custom strategy for optimistic locking  Database-specific ID generation
  • 3.
    April 14, 20053Hibernate in 60 Minutes [ ]Typical JDBC Problems  Massive duplication  Tied to specific database  Error-prone try/catch/finally  Relationships are really hard ○ N+1 selects problem ○ parent/child updates  delete all then add  Screen-specific DAOs for optimization
  • 4.
    April 14, 20054Hibernate in 60 Minutes [ ]Hibernate Questions  How hard is it to learn and use?  How invasive is it to my code?  What are the configuration headaches? ○ Yet another framework with XML files, JAR files, additional build complexity?  Does it simplify my life?
  • 5.
    April 14, 20055Hibernate in 60 Minutes [ ]What is Hibernate?  Java Object/Relational Mapping ○ Open source – LGPL ○ http://www.hibernate.org/ (JBoss Group)  Lets you avoid SQL  Works with (almost) all relational DBs ○ DB2, FrontBase, HSQLDB, Informix, Ingres, Interbase, Mckoi, MySQL, Oracle, Pointbase, PostgreSQL, Progress, SAP DB, SQL Server, Sybase, etc... ○ Or you can extend one of the Dialect classes
  • 6.
    April 14, 20056Hibernate in 60 Minutes [ ]What is Hibernate? (Cont'd)  Has a huge feature list ○ Go to their web site – we don't have time  Maps JavaBeans (POJOs) to tables ○ XML defines the mappings ○ Very few bean requirements  SQL is generated at app startup time ○ As opposed to bytecode manipulation ○ New database? No problem! Change a few props
  • 7.
    April 14, 20057Hibernate in 60 Minutes [ ]Avoiding SQL  Hibernate Query Language approach public User getByScreenName(String screenName) { try { return (User) getSession().createQuery( "from User u where u.screenName=:screenName") .setString("screenName", screenName) .uniqueResult(); } catch (HibernateException e) { throw new DaoException(e); } }  Code-based query API public User getByScreenName(String screenName) { return getUnique(Expression.eq("screenName", screenName)); } JavaBeans Property Name
  • 8.
    April 14, 20058Hibernate in 60 Minutes [ ]Sample Application Code Session session = getSessionFactory().openSession(); // assume we know the root category id is 1 Category rootCategory = (Category) session.load( Category.class, new Long(1)); // we can immediately traverse the collection of messages // without any additional Hibernate code for (Object msgObj : rootCategory.getMessages()) { Message msg = (Message) msgObj; // generics+XDoclet==bad System.out.println(“Subject: “ + msg.getSubject()); System.out.println(“Body: “ + msg.getBody()); System.out.println(); } session.close();
  • 9.
    April 14, 20059Hibernate in 60 Minutes [ ]Sample Code with Transaction Session sess = ... Transaction tx = sess.beginTransaction(); // find the root category using Criteria Criteria criteria = sess.createCriteria(Category.class); criteria.add(Expression.isNull("parentCategory")); Category rootCategory = (Category) criteria.uniqueResult(); // change something rootCategory.setDescription(“The Root Category”); tx.commit(); sess.close();
  • 10.
    April 14, 200510Hibernate in 60 Minutes [ ]Development Options  Start with the database ○ Use middlegen to generate mapping files ○ Use hbm2java to generate JavaBeans  Start with JavaBeans ○ Use XDoclet to generate mapping files ○ Use hbm2ddl to generate the database  Start with the XML mapping files ○ Hand-code the mapping files ○ Use both hbm2java and hbm2ddl C
  • 11.
    April 14, 200511Hibernate in 60 Minutes [ ]Hibernate Tutorial  Design the database  Code some persistent classes  Write an Ant buildfile ○ Generate the mapping files and hibernate.cfg.xml  Choose a strategy for sessions and transactions (Spring framework)  Write and test the DAOs  Add business logic and helper methods
  • 12.
    April 14, 200512Hibernate in 60 Minutes [ ]Database Design  Design your database first Categories PK id name description FK1 parentCategoryId Resources PK id name url description createdOn CategoriesResources PK,FK1 categoryId PK,FK2 resourceId Surrogate Keys Work Best many-to-one many-to-many
  • 13.
    April 14, 200513Hibernate in 60 Minutes [ ]Persistent Objects  POJOs - Plain Old Java Objects ○ No base class or interface requirement  Must have public no-arg constructor  Should have getter/setters ○ Or Hibernate can access fields directly ○ Hibernate uses JavaBeans property names  For mappings as well as in queries  Serializable is recommended  XDoclet tags are useful but not required
  • 14.
    April 14, 200514Hibernate in 60 Minutes [ ]My Base Class public class PersistentClass implements Serializable { private static final long serialVersionUID = 1; private Long id; /** * @hibernate.id * column="id" * unsaved-value="null" * generator-class="native" * access="field" */ public Long getId() { return id; } private void setId(Long id) { this.id = id; } } Hibernate assigns the id
  • 15.
    April 14, 200515Hibernate in 60 Minutes [ ]Category Class public class Category extends NameDescription { private static final long serialVersionUID = 1; private Set childCategories = new HashSet(); private Set resources = new HashSet(); private Category parentCategory; public Category() { } public Category(String name, String description) { super(name, description); } public Set getChildCategories() { return childCategories; } public void setChildCategories(Set childCategories) { this.childCategories = childCategories; } My base class, not Hibernate's
  • 16.
    April 14, 200516Hibernate in 60 Minutes [ ]Category (Cont'd) public Category getParentCategory() { return parentCategory; } public void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; } public Set getResources() { return resources; } public void setResources(Set resources) { this.resources = resources; } }
  • 17.
    April 14, 200517Hibernate in 60 Minutes [ ]Mapping Files  Generated by XDoclet, 1 per persistent bean <hibernate-mapping> <class name="com.ericburke.linkblog.model.Category" table="Categories"> <id name="id" column="id" type="java.lang.Long" unsaved-value="null"> <generator class="native"/> </id> <set name="childCategories" lazy="true" inverse="true" cascade="save-update"> <key column="parentCategoryId"/> <one-to-many class="com.ericburke.linkblog.model.Category"/> </set> <many-to-one name="parentCategory" class="com.ericburke.linkblog.model.Category" cascade="none" column="parentCategoryId" not-null="false"/> Or Java 5 Annotations
  • 18.
    April 14, 200518Hibernate in 60 Minutes [ ]Mapping Files (Cont'd) <set name="resources" table="CategoriesResources" lazy="true" cascade="save-update"> <key column="categoryId"/> <many-to-many column=”resourceId” class="com.ericburke.linkblog.model.Resource"/> </set> <property name="name" type="java.lang.String" column="name" length="255"/> <property name="description" type="java.lang.String" column="description" length="2000"/> </class> </hibernate-mapping>
  • 19.
    April 14, 200519Hibernate in 60 Minutes [ ]Xdoclet Tag Example /** * @hibernate.class table="Categories" */ public class Category extends NameDescription { /** * @hibernate.set cascade="save-update" inverse="true" * lazy="true" * @hibernate.collection-key column="parentCategoryId" * @hibernate.collection-one-to-many * class="com.ericburke.linkblog.model.Category" */ public Set getChildCategories() { return childCategories; } // no tags on the setters public void setChildCategories(Set childCategories) { }
  • 20.
    April 14, 200520Hibernate in 60 Minutes [ ]hibernate.cfg.xml <hibernate-configuration> <session-factory> <property name="dialect"> net.sf.hibernate.dialect.HSQLDialect</property> <property name="show_sql">true</property> <property name="use_outer_join">false</property> <property name="connection.username">sa</property> <property name="connection.driver_class"> org.hsqldb.jdbcDriver</property> <property name="connection.url"> jdbc:hsqldb:hsql://localhost/linkblog</property> <property name="connection.pool_size">5</property> <mapping resource="com/ericburke/linkblog/model/Category.hbm.xml"/> <mapping resource="com/ericburke/linkblog/model/Resource.hbm.xml"/> </session-factory> </hibernate-configuration> Generated by XDoclet, or use Spring's XML file
  • 21.
    April 14, 200521Hibernate in 60 Minutes [ ]Ant Buildfile  Invokes XDoclet ○ XDoclet ships with the Hibernate tasks ○ Generates mapping files and hibernate.cfg.xml  Hibernate includes tasks for ○ hbm2java – generates the persistent classes ○ hbm2ddl – generates the database  Classpath needs ○ Hibernate Jars, Hibernate extensions, XDoclet, JDBC driver JAR file Requires the persistent .class files in the taskdef's classpath
  • 22.
    April 14, 200522Hibernate in 60 Minutes [ ]HibernateUtil  Trivial examples show this class ○ Creates a SessionFactory in the static initializer Configuration cfg = new Configuration(); SessionFactory sessionFactory = cfg.configure("/hibernate.cfg.xml") .buildSessionFactory();  Provides access to a Session ThreadLocal public static Session getSession() { Session s = (Session) threadSession.get(); if (s == null) { s = sessionFactory.openSession(); threadSession.set(s); } return s;  APIs to begin/commit/rollback transactions
  • 23.
    April 14, 200523Hibernate in 60 Minutes [ ]DAOs  Insulate your code from Hibernate specifics  CRUD operations ○ I use Java 5 generics heavily ○ You can also use Spring for DAO support  Locating persistent objects ○ Use Hibernate queries for efficiency ○ From there, walk the graph using normal Java collections semantics  Detached objects can be challenging
  • 24.
    April 14, 200524Hibernate in 60 Minutes [ ]Servlet Filter public class HibernateFilter implements Filter { public void init(FilterConfig fc) throws ServletException { } public void destroy() { } public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { try { filterChain.doFilter(req, res); HibernateUtil.commitTransaction(); } finally { HibernateUtil.closeSession(); } } } Hibernate in Action, page 304
  • 25.
    April 14, 200525Hibernate in 60 Minutes [ ]Business Objects  A layer between your application code and the DAOs ○ Only allow business objects to hit the DAOs ○ Business objects and app code use persistent objects  Provide a consistent place to use AOP ○ try/catch/finally for transactions  Risk duplicating DAO code ○ Sometimes business object methods just delegate
  • 26.
    April 14, 200526Hibernate in 60 Minutes [ ]Architecture Summary AOP for Transactions Persistent Objects Application Code DAOs Hibernate Database XML Mappings Business Objects Keep an Open Session
  • 27.
    April 14, 200527Hibernate in 60 Minutes [ ]Gotchas  Must always have an open session ○ Seemingly innocent code like fetching a lazy collection bombs ○ Swing – open a session on event thread ○ Servlets – use a filter or Spring  Hibernate tasks do not abort Ant ○ No failonerror attribute ○ Watch the build output carefully  Test associations and collections heavily
  • 28.
    April 14, 200528Hibernate in 60 Minutes [ ]When Not to Use Hibernate  A horrible database design is forced on you ○ Many composite keys  If your application is mostly mass operations ○ See pg. 181 “Hibernate in Action” ○ You might exhaust available heap space  ??
  • 29.
    April 14, 200529Hibernate in 60 Minutes [ ]10 Reasons to Love Hibernate 1.Dynamic UPDATE generation – figure out which columns changed 2.Trying new databases 3.Traversing associations 4.Optimistic Locking 5.ID generation 6.No more DTOs 7.Query result paging 8.Automatic dirty checking 9.Good price 10.Good documentation