Go to content Go to sidebar

So you want to learn Hibernate

Me too. Unfortunately, I'm finding the learning curve just a bit steep – or maybe it's just that my brain is not wired the right way. I like to start with the simplest example that does something and then start playing from there. The examples in the Hibernate documentation weren't quite what I was looking for. For one thing, they all seemed to run inside an App Server. So here is my version of a simple Hibernate application.

Let's start with some book keeping. I'm using Java 1.4.1_01 on Mac OS X, Ant 1.5.1, Hibernate 2.0.1, and HSqlDB 1.7.1. I chose HSqlDB because I would like to run an in-process database at some point. Although I haven't tried any other databases, I would expect good results with any other database known to Hibernate. And I would also expect good results with closely related versions of Java and Ant. If you are in a hurry to play, then you can grab the example distribution and go to town (but see this warning first).

Now, on to my Ant build file.


<project default="all">
  <property name="HBM-HOME" location="/Projects/Java/hibernate" />
  <property name="JDBC"     location="/Projects/Server/hsqldb/lib/hsqldb.jar" />

<property name="src-dir" location="src" /> <property name="cfg-dir" location="cfg" /> <property name="obj-dir" location="obj" /> <property name="TALK" value="false" />

<path id="classpath.base"> <pathelement location="${obj-dir}" /> <pathelement location="${HBM-HOME}/hibernate2.jar" /> <fileset dir="${HBM-HOME}/lib" includes="**/*.jar" /> <pathelement location="${JDBC}" /> </path> <path id="classpath.run"> <pathelement location="${cfg-dir}" /> <path refid="classpath.base" /> </path>

<target name="init"> <mkdir dir="${obj-dir}" /> </target>

<target name="compile" depends="init"> <javac srcdir="${src-dir}" destdir="${obj-dir}" > <classpath refid="classpath.base" /> </javac> </target> <target name="clean-compile"> <delete verbose="${TALK}" dir="${obj-dir}" /> </target>

<target name="run" depends="compile"> <java classname="Main" fork="true"> <classpath refid="classpath.run" /> </java> </target>

<target name="dist"> <jar destfile="distrib.jar" basedir="." includes="build.xml,src/**,cfg/**" excludes="src/prj.el" /> </target> <target name="clean-dist"> <delete VERBOSE="${TALK}" file="distrib.jar"/> </target>

<target name="all" depends="run" /> <target name="clean" depends="clean-compile,clean-dist" /> </project>

<!-- $Id: build.xml,v 1.6 2003/07/07 19:29:01 dwight Exp $ -->

And here is where all the action is. We start with a Configuration object that specifies how Hibernate will interact with the underlying Database and add a mapping for the hb.Keyword.class (hibernate will load the file hb/Keyword.hbm.xml from the CLASSPATH). Then we create the Session that acts as a service for persistent objects (via a SessionFactory). Finally, we create a Transaction and save a Keyword object via the Session object.


//
// $Id: Main.java,v 1.3 2003/07/07 19:09:33 dwight Exp $
//
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.HibernateException;

import hb.*;


public class Main {

public static void main ( String[] args ) throws MappingException, HibernateException { Configuration cfg = new Configuration(); cfg.addClass( hb.Keyword.class );

SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession();

Transaction tx = null; Keyword kw = new Keyword( 1,"red" ); try { tx = session.beginTransaction(); session.save( kw ); tx.commit(); } catch ( HibernateException he ) { if ( tx != null ) tx.rollback(); throw he; } finally { session.close(); } } }

Now let's take a look at our configuration files. First, the hibernate.properties file. This specifies that we'll be using HSqlDB and how the application should connect to HSqlDB server instance.


#
#
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:hsql:\//localhost
hibernate.connection.username=user
hibernate.connection.password=user
hibernate.connection.pool_size=2
#
hibernate.dialect=net.sf.hibernate.dialect.HSQLDialect
#
# $Id: hibernate.properties,v 1.1 2003/07/05 21:39:57 dwight Exp $
#

And finally, the mapping from the hb/Keyword class to the KEYWORDS database table (I'm skipping the Keyword.java file because it's mostly boilerplate: 2 instance variables, 2 constructors, 2 pairs of get/set methods. Hibernate requires accessors and mutators for persistent fields and a default constructor). The use of the identity generator requires that the KEYWORDS.id column be defined as type identity – you'll need to look at Hibernate Identity Columns and Sequences to use a database other than HSqlDB.


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
          "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping> <!-- table created by: CREATE TABLE KEYWORDS ( ID IDENTITY, NAME VARCHAR(25) ); --> <class name="hb.Keyword" table="keywords">

<id name="id" type="integer" column="id"> <generator class="identity"/> </id>

<property name="name" column="NAME" not-null="true" unique="true" /> </class>

</hibernate-mapping>

<!-- $Id: Keyword.hbm.xml,v 1.3 2003/07/08 19:18:30 dwight Exp $ -->

Warning: this application persists keyword objects without regard for any existing persistent keyword objects. Consequently, another row will be added to the database with each execution. We'll take a look at fixing that later.

With that warning out of the way, you're ready to get the example distribution and go to town. Here is the output from a sample run on my system (somewhat modified for brevity and format):


$ ant
Buildfile: build.xml

init:

compile:

run: [java] Jul 9, 2003 7:42:38 AM net.sf. ... .Environment <clinit> [java] INFO: Hibernate 2.0.1 [java] Jul 9, 2003 7:42:38 AM net.sf. ... .Environment <clinit> [java] INFO: loaded properties from resource hibernate.properties: { ... } [java] Jul 9, 2003 7:42:38 AM net.sf. ... .Environment <clinit> [java] INFO: using CGLIB reflection optimizer [java] Jul 9, 2003 7:42:38 AM net.sf. ... .Environment <clinit> [java] INFO: JVM proxy support: true [java] Jul 9, 2003 7:42:38 AM net.sf. ... .Configuration addClass [java] INFO: Mapping resource: hb/Keyword.hbm.xml [java] Jul 9, 2003 7:42:41 AM net.sf. ... .Binder bindRootClass [java] INFO: Mapping class: hb.Keyword -> keywords [java] Jul 9, 2003 7:42:42 AM net.sf. ... .SessionFactoryImpl <init> [java] INFO: building session factory [java] Jul 9, 2003 7:42:43 AM net.sf. ... .Dialect <init> [java] INFO: Using dialect: net.sf.hibernate.dialect.HSQLDialect [java] Jul 9, 2003 7:42:43 AM net.sf. ... .DriverManagerConnectionProvider configure [java] INFO: Hibernate connection pool size: 2 [java] Jul 9, 2003 7:42:43 AM net.sf. ... .DriverManagerConnectionProvider configure [java] INFO: using driver: org.hsqldb.jdbcDriver at URL: jdbc:hsqldb:hsql:\//localhost [java] Jul 9, 2003 7:42:43 AM net.sf. ... .DriverManagerConnectionProvider configure [java] INFO: connection properties: {user=user, password=user} [java] Jul 9, 2003 7:42:43 AM net.sf. ... .SessionFactoryImpl <init> [java] INFO: Use outer join fetching: false [java] Jul 9, 2003 7:42:43 AM net.sf. ... .SessionFactoryImpl <init> [java] INFO: Use scrollable result sets: true [java] Jul 9, 2003 7:42:46 AM net.sf. ... .SessionFactoryObjectFactory addInstance [java] INFO: no JDNI name configured [java] Jul 9, 2003 7:42:46 AM net.sf. ... .SessionFactoryImpl <init> [java] INFO: Query language substitutions: {}

all:

BUILD SUCCESSFUL Total time: 18 seconds

Now that we're here, I have to say that getting started with Hibernate wasn't so bad. It just wasn't obvious that it would turn out to be this simple.

13 Oct 05: Hibernate documentation links updated. Thanks to Lee Irvine.



Disclaimer: I don't claim to be an expert on hibernate. Please send comments and corrections.