Download as pdf or txt
Download as pdf or txt
You are on page 1of 51

Professional Open Source

Hibernate Basics
Hello World again

JBoss, Inc. 2003, 2004, 2005.

02/23/07

Hello World I

The Hello World program prints messages


To demonstrate Hibernate, lets define a persistent message we use a Message persistent class, POJO style
package hello; public class Message { private Long id; private String text; public String getText() { return text; } public void setText(String text) { this.text = text; } }

Professional Open Source


JBoss, Inc. 2003, 2004.

Hello World II

Messages don't have to be persistent!


we can use our persistent classes outside of Hibernate Hibernate is able to manage persistent instances but POJO persistent classes don't depend on Hibernate

Message message = new Message("Hello World"); System.out.println( message.getText() );

Professional Open Source


JBoss, Inc. 2003, 2004.

Hello World III

Let's persist a message with Session and Transaction:


Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Message message = new Message("Hello World"); session.save(message); tx.commit(); session.close();

Hibernate executes this SQL:

insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT) values (1, 'Hello World')

Professional Open Source


JBoss, Inc. 2003, 2004.

Hello World IV

Let's show all persistent messages:


Session newSession = getSessionFactory().openSession(); Transaction newTransaction = newSession.beginTransaction(); List messages = newSession.createQuery("from Message").list(); System.out.println( messages.size() + " message(s) found:" ); for ( Iterator iter = messages.iterator(); iter.hasNext(); ) { Message message = (Message) iter.next(); System.out.println( message.getText() ); } newTransaction.commit(); newSession.close();

select m.MESSAGE_ID, m.MESSAGE_TEXT from MESSAGES m


Professional Open Source
JBoss, Inc. 2003, 2004.

Hello World V

Let's update a message:


Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); // 1 is the generated id of the first message Message message = session.get( Message.class, new Long(1) ); message.setText("Greetings Earthling"); tx.commit(); session.close();

select m.MESSAGE_TEXT from MESSAGES m where m.MESSAGE_ID = 1 update MESSAGES set MESSAGE_TEXT = Greetings Earthling'

Notice that we did not explicitly call any update() method - automatic dirty checking gives us more flexibility when organizing data access code!
Professional Open Source
JBoss, Inc. 2003, 2004.

Hello World VI

XML mapping metadata:


<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sf.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="hello.Message" table="MESSAGES"> <id>...</id> <property name="text" column="MESSAGE_TEXT"/> </class> </hibernate-mapping>
Professional Open Source
JBoss, Inc. 2003, 2004.

Professional Open Source

Advanced class and property mappings


Entities, fine-grained object mappings, and inheritance

JBoss, Inc. 2003, 2004, 2005.

02/23/07

Metadata options

First, we'll have to decide how we'd like to write metadata


Hibernate3 XML mapping files Hibernate3 XDoclet annotations EJB3/Hibernate3 JDK 5.0 annotations

The most popular and primary method is XML mapping files. Many Hibernate users have good experience with XDoclet. EJB3/Hibernate3 annotations are currently available in beta only, but this is expected to be stable very soon.

Professional Open Source


JBoss, Inc. 2003, 2004.

XML Mapping files

<hibernate-mapping" schema="AUCTION"> <class name="User" table="USERS" <id>...</id> <property name="login" column="LOGIN"/> <set name="items" ... </class> </hibernate-mapping>

Advantages
wide adoption and documentation availability clear separation from Java source

Disadvantages
difficult in refactoring needs special XML editor for auto-completion

Professional Open Source


JBoss, Inc. 2003, 2004.

10

XDoclet annotations

/** * @hibernate.class * table="CATEGORY" */ public class Category { /** * @hibernate.property */ public String getName() { return name; } ...

Advantages
Refactoring is easy Runs on all JDK versions

Disadvantages
not type-safe and auto-completion only available in IDEs Needs pre-processing step at build-time The XDoclet project is not making much progress
Professional Open Source
JBoss, Inc. 2003, 2004.

11

EJB3/Hibernate3 annotations for JDK 5.0

import javax.persistence.*; @Entity(access = AccessType.FIELD) public class User { @Id(generate = GeneratorType.AUTO) Long id; String loginName; @OneToMany(cascade = CascadeType.PERSIST) @JoinColumn(name = "USER_ID") Set<Item> items = new HashSet<Item>();

Advantages
Refactoring is easy Externalization of physical (or all) annotations to XML files Type-safe and no pre-processing required

Disadvantages
Needs JDK 5.0
Professional Open Source
JBoss, Inc. 2003, 2004.

12

Our example application


CaveatEmptor is an online auction system we have the following domain model:

Category
0..* 0..* 0..*

http://caveatemptor.hibernate.org

Item

0..* sells

Bid User BillingDetails

CreditCard
JBoss, Inc. 2003, 2004.

BankAccount
Professional Open Source

13

Fine-grained domain models

<< Entity >>

User

homeAddress

<< Value type >>

Address

loginName: String <<V>> homeAddress: Address <<V>> items: Set <<E>>

Entities (Item, User, Category)


instances have an independent lifecycle instances support shared references have a database identifier

Value types (String, Date, Integer, long, Address, MonetaryAmount)


consider composition in UML model have a dependent lifecycle don't support shared references don't have a database identifier
Professional Open Source
JBoss, Inc. 2003, 2004.

14

Mapping entities

We use the <class> element for each persistent entity class


by default, all columns are included in SQL INSERT and UPDATE override with dynamic insert and update, no SQL generation on startup

<hibernate-mapping package="org.hibernate.auction.model" default-cascade="save-update" default-access="field" default-lazy="false"> <class name="User" table="USER" dynamic-insert="true" dynamic-update="true" persister="MyLDAPPersister"> <id>...</id> </class>

...

Entity classes need a database identifier...


Professional Open Source
JBoss, Inc. 2003, 2004.

15

About good primary keys

The primary key for our tables should be


unique: no duplicate values ever constant: value is never updated required: never null

Types of primary keys:


natural key: an attribute that is unique by virtue of its business meaning (any composite key is a natural key) surrogate key: an attribute generated by the system, with no meaning to the user, and no business semantics

For new systems, we recommend the use of surrogate keys if no good natural candidate keys can be found - this strategy makes schema evolution simpler.
Professional Open Source
JBoss, Inc. 2003, 2004.

16

Database identity in Hibernate

We add an identifier property to persistent entity classes


the value of that property is the primary key value the name should always be the same for all classes, e.g. id

Should the identifier property be public?


if we use the identifier outside of persistence, e.g. in web applications it is a convenient handle to a particular instance lookup by identifier is an especially efficient operation in Hibernate we usually have a public getter and a private setter
public class Category { private Long id = null; public Long getId() { return this.id; } private void setId(Long id) { this.id = id; } }
Professional Open Source
JBoss, Inc. 2003, 2004.

17

Identity mapping

Identifier property mappings


the identifier property type may be any Hibernate type the identifier generation strategy may be customized identifier properties are actually optional, but strongly recommended (if you dont have an identifier property, just omit name in the mapping)

<class name="Category" table="CATEGORY"> <id name="id" column="CATEGORY_ID" type="long"> <generator class="native"/> </id> ... </class>

Professional Open Source


JBoss, Inc. 2003, 2004.

18

Identifier generation strategies



increment incrementing value, unique to the JVM (long, short, int) native picks other strategies, depending on the database capabilities (long, short, int) identity identity column types in DB2, MS SQL Server, Sybase, MySQL, HSQL, Postgres, etc (long, short, int) sequence incrementing sequence in DB2, PostgreSQL, Oracle, HSQL, etc (long, short, int) hilo high- and low-value algorithm, unique to database instance (long, short, int) seqhilo high- and low-value algorithm based on a sequence, unique to database instance (long, short, int) uuid Hibernate UUID algorithm, unique to a subnet (String) guid database GUID algorithm for MySQL, Oracle and MS SQL Server, introduced in Hibernate3 (String) Professional Open Source
JBoss, Inc. 2003, 2004.

19

Class inheritance hierarchies

1..*

User

default

BillingDetails

CreditCard

BankAccount

First strategy, table per concrete class:


<< table >> CREDIT_CARD
CREDIT_CARD_ID << PK >> OWNER NUMBER TYPE EXP_DATE

<< table >> BANK_ACCOUNT


BANK_ACCOUNT_ID << PK >> OWNER NUMBER BANK_NAME BANK_SWIFT

We can map only the concrete classes (implicit polymorphism), or...


Professional Open Source
JBoss, Inc. 2003, 2004.

20

Using UNION subclass mappings

<class name="BillingDetails" abstract="true"> <property name="owner" column="OWNER"/> ... <union-subclass name="CreditCard" table="CREDIT_CARD> <property name="type" column="CREDIT_CARD_TYPE"/> ... </union-subclass> ... </class>

polymorphic queries result in a UNION instead of several selects many-valued assocations to superclass result in a UNION but have to be bidirectional (inverse="true") single-valued associations to superclass are still problematic, no foreign key constraint can be created
Professional Open Source
JBoss, Inc. 2003, 2004.

21

Table per class hierarchy

<< table >> BILLING_DETAILS


BILLING_DETAILS_ID << PK >> BILLING_TYPE << discriminator >> OWNER NUMBER CREDIT_CARD_TYPE CREDIT_CARD_EXP_DATE BANK_ACCOUNT_NAME BANK_ACCOUNT_SWIFT

note the type discriminator column best performance, polymorphic queries and associations subclass columns must be nullable! we use the Hibernate <subclass> mapping

Professional Open Source


JBoss, Inc. 2003, 2004.

22

Mapping a class hierarchy to a single table

<class name="BillingDetails" table="BILLING_DETAILS"> <id name="id" column="BILLING_DETAILS_ID"> <generator class="native"/> </id> <discriminator column="BILLING_TYPE type=string/> <property name="name" column="OWNER"/> ... <subclass name="CreditCard" discriminator-value="CC"> <property name="type" column="CREDIT_CARD_TYPE"/> ... </subclass> ... </class>

<subclass> elements can be nested

Professional Open Source


JBoss, Inc. 2003, 2004.

23

Mapping a class hierarchy to a single table

<class name="BillingDetails" table="BILLING_DETAILS"> <id name="id" column="BILLING_DETAILS_ID"> <generator class="native"/> </id> <discriminator type=string formula=case when CREDIT_CARD_TYPE is null then BA else CC end/> <property name="name" column="OWNER"/> ... <subclass name="CreditCard" discriminator-value="CC"> <property name="type" column="CREDIT_CARD_TYPE"/> ... </subclass> ... </class>

If there is no discriminator column, we can use a SQL expression These can be very complicated if you like!
Professional Open Source
JBoss, Inc. 2003, 2004.

24

Splitting up the mapping files

You can split an inheritance mapping into several files:


<class name="BillingDetails" table="BILLING_DETAILS"> <id name="id" column="BILLING_DETAILS_ID"> <generator class="native"/> </id> <discriminator column="BILLING_TYPE type=string/> <property name="name" column="OWNER"/> ... </class>

<subclass name="CreditCard" extends="BillingDetails> discriminator-value=CC> <property name="type" column="CREDIT_CARD_TYPE"/> ... </subclass>

Professional Open Source


JBoss, Inc. 2003, 2004.

25

Table per subclass

<< table >> BILLING_DETAILS


BILLING_DETAILS_ID <<PK>> OWNER NUMBER

<< table >> CREDIT_CARD


CREDIT_CARD_ID <<PK>> <<FK>> TYPE EXP_DATE

<< table >> BANK_ACCOUNT


BANK_ACCOUNT_ID <<PK>> <<FK>> BANK_NAME BANK_SWIFT

normalized model polymorphic associations even to particular subclasses we use the Hibernate <joined-subclass> mapping
Professional Open Source
JBoss, Inc. 2003, 2004.

26

Mapping a joined subclass to normalized tables

<class name="BillingDetails" table="BILLING_DETAILS"> <id name="id" column="BILLING_DETAILS_ID"> <generator class="native"/> </id> <property name="name" column="OWNER"/> ... <joined-subclass name="CreditCard"> <key column="CREDIT_CARD_ID"/> <property name="type" column="CREDIT_CARD_TYPE"/> ... </joined-subclass> ... </class>

difficult to implement by hand, performance of outer joins is an issue ad hoc reporting might be more complex

Professional Open Source


JBoss, Inc. 2003, 2004.

27

Professional Open Source

Loading and storing objects


Hibernate's Session, Transaction, and Query interfaces

JBoss, Inc. 2003, 2004, 2005.

02/23/07

28

Object state and transition overview

new

Transient
garbage collection delete()

get() load() list() iterate() scroll() uniqueResult()

save() saveOrUpdate() persist()

Persistent
evict() close()* clear()* update() saveOrUpdate() lock() merge()

garbage collection

Detached
* affects all instances in a Session

Professional Open Source


JBoss, Inc. 2003, 2004.

29

Object states explained

Transient instances
have no database state or database identity made persistent with save() or persist()

Persistent instances
have assigned database identity are managed and transactional, dirty checked by Hibernate made transient with delete() made detached with close() or evict() are reloaded with refresh()

Detached instances
have database identity but are not associated with a Session made persistent with update(), saveOrUpdate(), or merge()

Professional Open Source


JBoss, Inc. 2003, 2004.

30

Saving an object

Persisting a transient instance:

User user = new User(); user.getName().setFirstName("John"); user.getName().setLastName("Doe"); Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Long newId = session.save(user); // session.save(user, new Long(1234) ); tx.commit(); session.close();

The state of user is detached, after the Session has been closed.
Professional Open Source
JBoss, Inc. 2003, 2004.

31

Loading an object

Using a known identifier value:

Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Object usr = session.get(User.class, 1234); //Object usr = session.load(User.class, 1234); tx.commit(); session.close();

The get() method returns null if the object can't be found, the load() throws an exception. The exception might also be thrown on first access of a proxy.
Professional Open Source
JBoss, Inc. 2003, 2004.

32

The scope of identity

Hibernate guarantees identical objects in a particular Session:

Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Object a = session.load(Item.class, new Long(1234) ); Object b = session.load(Item.class, new Long(1234) ); if ( a == b ) System.out.println("a and b are identical"); tx.commit(); session.close();

Instances outside of this scope are detached.

Professional Open Source


JBoss, Inc. 2003, 2004.

33

Instances outside the identity scope

Session session1 = HibernateUtil.getSession(); Transaction tx1 = session.beginTransaction(); Object itemA = session1.load(Item.class, new Long(1234) ); tx1.commit(); session1.close(); Session session2 = HibernateUtil.getSession(); Transaction tx2 = session.beginTransaction(); Object itemB = session2.load(Item.class, new Long(1234) ); tx2.commit(); session2.close(); Set allObjects = new HashSet(); allObjects.add(itemA); allObjects.add(itemB); System.out.println(allObjects.size()); // How many?

We have to implement equals() & hashCode() for classes. Don't use the identifer, but a business key.
Professional Open Source
JBoss, Inc. 2003, 2004.

34

Persisting detached instances

Reattaching an object in a new unit of work:

// "usr" has been loaded in a previous Session usr.setPassword("secret"); Session sessionTwo = HibernateUtil.getSession(); Transaction tx = sessionTwo.beginTransaction(); sessionTwo.update(usr); usr.setLoginName("jonny"); tx.commit(); sessionTwo.close();

Hibernate can automatically check versions for optimistic concurrency control (more later).
Professional Open Source
JBoss, Inc. 2003, 2004.

35

Automatic state detection

Hibernate can automatically detect if an object is new (transient) and what is old (detached):
Session session = HibernateUtil.getSession() Transaction tx = session.beginTransaction(); session.saveOrUpdate(newOrOld); tx.commit(); session.close();

Hibernate by default instantiates a fresh object and compares it to the given instance. You can customize this behavior in your mapping files or with a custom routine using interception.
Professional Open Source
JBoss, Inc. 2003, 2004.

36

Transitive persistence

Instead of working with only single objects, Hibernate can cascade state changes to associated entity instances. Cascade attributes can be set individually for each association:
<many-to-one name="category" cascade="none"/> <set name="items" cascade="persist, merge, save-update">... <set name="children" cascade="all, orphan-delete">...

Available cascade options: persist, merge, save-update, delete, lock, refresh, evict, replicate, orphan-delete, all
Professional Open Source
JBoss, Inc. 2003, 2004.

37

Merging detached objects

Reattachment throws an exception if the "same" instance is already persistent in the Session. We have to merge the changes:
// "c" is detached and has Id "1234" c.setPassword("secret"); Session sessionTwo = HibernateUtil.getSession(); Transaction tx = sessionTwo.beginTransaction(); User a = (User) session.load(User.class, "1234"); User b = (user) session.merge(c); (a == b) // true (a == c) // false (b == c) // false a.getPassword() // secret b.getPassword() // secret tx.commit(); sessionTwo.close();
Professional Open Source
JBoss, Inc. 2003, 2004.

38

Summary

Hibernate defines three object states:


transient, persistent, detached

Hibernate's native methods offer saving of transient and reattachment of detached instances. EJB3 adds an alternative saving operation and the ability to merge detached object state into persistent state. Objects outside of the scope of identity have to implement equals() and hashCode() correctly if they are compared. A business key is the prefered way, since database identifiers may change during save. All state management operations can be cascaded to associated objects, saving API calls. Cascading options can be declared finegrained in mapping metadata.

Professional Open Source


JBoss, Inc. 2003, 2004.

39

Professional Open Source

Deployment and configuration


Deployment environments and configuration options

JBoss, Inc. 2003, 2004, 2005.

02/23/07

40

Configuration: non-managed environments

In a non-managed environment (eg. Tomcat), we need a JDBC connection pool:


C3P0, Proxool, custom ConnectionProvider

Non-managed environment Application


JSP Servlet main()

Hibernate
Session Transaction Query Connection Pool

Professional Open Source


JBoss, Inc. 2003, 2004.

41

Using C3P0 with hibernate.properties

Let's configure Hibernate to use C3P0 connection pooling


Hibernate automatically loads hibernate.properties from a root directory of the classpath
hibernate.connection.driver_class = org.postgresql.Driver hibernate.connection.url = jdbc:postgresql://localhost/auctiondb hibernate.connection.username = auctionuser hibernate.connection.password = secret hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect hibernate.c3p0.min_size = 5 hibernate.c3p0.max_size = 20 hibernate.c3p0.timeout = 1800 hibernate.c3p0.max_statements = 50 Hibernate.c3p0.validate = true

Don't forget to set the SQL dialect!

Professional Open Source


JBoss, Inc. 2003, 2004.

42

Other configuration options

Instead of using a hibernate.properties file, we may also


pass an instance of Properties to Configuration programmatically set System properties using java -Dproperty=value use a hibernate.cfg.xml file in the classpath

The XML-based configuration is almost equivalent to the properties, it has some more features (cache tuning). The XML file overrides the hibernate.properties options. We usually prefer the XML configuration file, especially in managed environments.

Professional Open Source


JBoss, Inc. 2003, 2004.

43

Managed environments

Hibernate can be used in an application server:


Managed environment Application
EJB EJB EJB

Hibernate
Session Transaction Query Resource Manager Transaction Manager

Each database has it's own SessionFactory!

Professional Open Source


JBoss, Inc. 2003, 2004.

44

Managed environment with XML configuration file

<hibernate-configuration> <session-factory name="java:hibernate/SessionFactory"> <property name="show_sql">true</property> <property name="connection.datasource"> java:/comp/env/jdbc/HelloDB </property> <property name="transaction.factory_class"> org.hibernate.transaction.CMTTransactionFactory </property> <property name="transaction.manager_lookup_class"> org.hibernate.transaction.JBossTransactionManagerLookup </property> <property name="dialect"> org.hibernate.dialect.PostgreSQLDialect </property> <mapping resource="hello/Message.hbm.xml"/> </session-factory> </hibernate-configuration>
Professional Open Source
JBoss, Inc. 2003, 2004.

45

Hibernate as JMX MBean

Hibernate comes with a standard JMX MBean (org.hibernate.jmx.HibernateService) that is usable in any MBeanServer. Advantages
Defines a standard way to configure/manage Hibernate (although descriptors vary between MBeanServer implementations) Allows runtime configuration changes through the MBeanServers administration interface Exposes the SessionFactory through JNDI after MBean start for application usage

Disadvantages
JMX does not define a standard MBean lifecycle the MBean must be manually started after deployment the MBean must be manually stopped on undeployment

Professional Open Source


JBoss, Inc. 2003, 2004.

46

Integrated deployment in JBoss AS

JBoss Application Server has a microkernel - all services are registered as JMX MBeans. The org.jboss.hibernate package defines a number of services to integrate Hibernate into JBoss AS Advantages:
Automatic startup and shutdown (no more static HibernateUtil) SessionFactory available via JNDI after MBean deployment Special packaging format (HAR) makes bundling/deploying even easier No need to specify mappings; they are discovered Integration with other JBoss services

Disadvantages:
HAR format and service descriptor (hibernate-service.xml) are proprietary to JBoss AS
Professional Open Source
JBoss, Inc. 2003, 2004.

47

HAR archives

A HAR defines a Hibernate deployment


.har extension (or directory name ends in .har/ for exploded) Contains a meta-inf/hibernate-service.xml file which describes/configures the MBeans to be deployed (org.jboss.hibernate.jmx.Hibernate) Contains POJO domain classes and mappings (Java package structure) (Optional) Contains any dependency jars (e.g. ehcache.jar) (Optional) Any application classpath resources (the HAR is added to the deployment classpath)

A HAR can also be nested within an EAR


the EAR's meta-inf/jboss-app.xml must define the har as a module:
<module> <har>har-file-name-relative-to-ear-root.har</har> </module>

Professional Open Source


JBoss, Inc. 2003, 2004.

48

Sample HAR structure

caveatemptor-app.har ehcache.jar \---META-INF hibernate-service.xml \---org \---hibernate \---auction +---facade \---model Item.class Item.hbm.xml ...

The required JARs for Hibernate are picked up from ${server}/deploy/jboss-hibernate.deployer directory.

Professional Open Source


JBoss, Inc. 2003, 2004.

49

The service descriptor (hibernate-service.xml)

<?xml version="1.0"?> <server> <mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.har:service=MyHibernateFactory"> <depends>jboss:service=Naming</depends> <depends>jboss:service=TransactionManager</depends> <depends>jboss.jca:service=LocalTxCM,name=PostgresDS</depends> <attribute name=SessionFactoryName">java:/hibernate/MySF</attribute> <attribute name="DatasourceName">java:/PostgresDS</attribute> <attribute name="Dialect">org.hibernate.dialect.PostgreSQLDialect</attribute> <attribute name="CacheProviderClass"> org.hibernate.cache.TreeCacheProvider </attribute> </mbean> </server>

Professional Open Source


JBoss, Inc. 2003, 2004.

50

Its well DRC Time!!

Professional Open Source


JBoss, Inc. 2003, 2004.

51

You might also like