OR Mapping with Hibernate
Persistence in OO Apps
In an object oriented application, persistence allows an
object to outlive the process that created it. The state of an object can be stored to a disc, and an object with the same state can be re-created at some point in future. Persistence Technologies:
JDBC JDO iBATIS TopLink EJB 2.1 Entity Beans
Why ORM?
We want to work with
objects having behavior, not rows and columns of data. Object-relational paradigm mismatch.
Presentation Tier
Business Tier
Java Developers
Persistence Tier
Object-relational paradigm mismatch
DB
DBAs
Paradigm Mismatch
The problem of Subtypes Problems related to Associations The problem of Identity The problem of Granularity Example- MegaMusic- an imaginary entertainment business
Artist
id firstName
artist
Concert
id title date venue
concert
lastName description concerts
artists
The problem of subtypes
Artist
id firstName lastName description concerts
Java supports type inheritance. A table in
SQL DB is not a type. SQL DB products dont support type of table inheritance. No polymorphic association.
Rock Artist
wishList genre guitarType drumType
So how does ORM help? Inheritance Mapping Table per class hierarchy Table per subclass Table per concrete class Also, with Hibernate, you can fire polymorphic queries
preferences
Association problems
OOPL represents associations using object references (HAS-A
relationship). In the relation world, associations are represented as foreign keys. Java relationships can be many-to-many. To represent many-to-many relationships btw two relations we need a join table which doesnt appear anywhere in the domain model. Artist
id firstName
artist
Concert
id
Artist_Concert
concert
title date
lastName description concerts
artist_id
artist
venue
artists
concert_id
concert
The problem of Identity
Identity of Java objects can be
expressed as: Object Identity (checked with ==) Object Equality (boolean equals(Object)) The identity of a DB row is expressed as the primary key value.
DB
JVM Heap
artist
artist
artist
Two objects which are
different in JVM heap can represent the same DB row.
The problem of Granularity
Concert
id title
concert
Granularity refers to the size of
the type youre working with. The domain model offers three levels of granularity: Concert Venue String Whereas, the relational DBs offer just two levels (next slide).
date artists venue
Venue
country state street zip
Granularity (contd.)
Concert
id
The relational DBs
Concert
id
title date artists
concert
title
concert
date artists
venue
offer just two levels: Table such as Concert and, Columns such as country, state .. What does OR Mapping Provide? Association Mappings
country state street zip
Venue
country state street zip
Persistence Implementation
There are various ways the persistence layer can be
implemented: Hard-coding with SQL/JDBC (more development and maintenance efforts are required) XML Persistence (just another text file; no capabilities for DB mgt. ) Using Object Serialization Other ORM Solutions (iBATIS, JDO, TopLink, JPA) EJB 2.1 Entity Beans.
Problems with Object Serialization
A serialized network of interconnected objects can only
be accessed as a whole; its impossible to retrieve any data from the stream without desterilizing the whole stream. Its impossible to access or update a single object or a subset of objects independently. Loading and overwriting an entire network of objects causes hits performance.
Hibernate vs. Entity Beans
EJB 2.1 Programming Model
EJB 2.1 Complex Programming Model
ejb-jar.xml
<<Home Interface>>
Boilerplate code
Entity Class
Needs heavyweight app server Persistence is not standardized
No support for Entity Inheritance
Hbernate Programming Model
Hibernate Entity classes are POJOs No dependency on API No EJB container required No XML required (use Java 5 Annotations)
POJO Beans
Mapping File (optional)
Robust support for Inheritance Mappings
Hibernate Benefits
Transparent & Declarative
Presentation Tier
Business Tier
Java Developers
Persistence Tier
Persistence Productivity Maintainability Performance Vendor Independence
Hibernate
Object-relational paradigm synchronization
DB
DBAs
Hibernate Goals
Do less work and have a happy DBA. No error prone JDBC code is required.
No manual handling of JDBC ResultSet No Object Conversion No hard coded SQL No Value Object Design Pattern No preexisting DB schema required No need to re-factor to support different DB vendors
Hibernate Mission Statement
Defining Transparent Persistence
Any class can be a persistent class. No interfaces have to be implemented. No persistent superclasses have to be extended.
Hibernate- The Big Picture
Java SE 1.4
Java SE 5.0
Entity Manager Hibernate Core XML Metadata Annotations Hibernate Core XML Metadata
Annotations- new Java language feature introduced in Java SE 5. Hibernate Annotations + Hibernate Entity Manager = EJB 3.0 JPA sub spec
Architecture
Architecture
SessionFactory
A thread-safe global object. Theres one SessionFactory per DB. Creating a SessionFactory is expensive to create. Factory for Sessions. Instantiated once!
Session
A single-threaded, short lived object representing conversation btw the app and the persistent store. A non-threadsafe object that performs a single unit of work. Wraps a JDBC connection. Acts as a factory for transactions. Is inexpensive to create!
Transaction
A single-threaded, short lived object that represents an atomic unit of work. Abstracts app from underlying JDBC transaction. A Session might span several Transactions in some cases.
First Hibernate Application
Following steps are involved in developing a Hibernate powered O/R mapping app: 1. Create POJO Bean (Entity Class) 2. Write Mapping File 3. Write Hibernate Configuration File 4. Prepare Hibernate Startup and Helper Class 5. Write the Client Code
Creating POJO Beans
Persistent classes are implemented as POJO beans. Not all instances of a persistent class are considered to
be in the persistent state - an instance may instead be transient or detached
POJO Programming Rules
Implement a no-argument constructor.
Provide a default constructor with at least package visibility. The no-argument constructor is required to instantiate an object of this class through reflection. Provide an identifier property (optional)
This property maps to the primary key column of a database table
POJO Programming Rules
Prefer non-final classes (optional)
Declare accessors and mutators for persistent fields (optional) Hibernate can also access fields directly, the benefit of accessor methods is robustness for refactoring
Mapping File
What is a mapping file?
Hibernate needs to know how to load and store objects of the persistent class. This is where the Hibernate mapping file comes into play. The mapping file tells Hibernate what table in the database it has to access, and what columns in that table it should use.
Structure of a Mapping File
How does the Hibernate mapping file look like?
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping3.0.dtd"> <hibernate-mapping> [...] </hibernate-mapping>
Structure of a Mapping File
Between the two hibernate-mapping tags, include a class
element. All persistent entity classes need such a mapping, to a table in the SQL database:
<hibernate-mapping package="com.ibm"> <class name="Employee" table="IBM_EMPLOYEE"> . </class> </hibernate-mapping>
Generating DB row Identifier
<id name="empid" column="EMP_ID"> <generator class="native"/> </id>
Persisting Class properties
<property name="empName" column="EMP_NAME" length="40" type="string" /> <property name="empDesg" column="EMP_DESG" type="string" /> <property name="salary" column="EMP_SAL" />
Mapping File
What should be the name of the mapping file?
The naming of mapping files can be arbitrary, however the hbm.xml suffix is a convention in the Hibernate developer community.
Mapping File
Where should be the mapping file located?
The mapping file should be present in the classpath.
This mapping file should be saved as Employee.hbm.xml, right in the directory next to the Employee Java class source file.
Mapping File
Where is the mapping file referred from?
All mapping files are referred from Hibernate configuration file
Hibernate Configuration
Whats the purpose of Hibernate configuration file?
Hibernate is the layer in your application which connects to this database, so it needs connection information. The connections are made through a JDBC connection pool, which we also have to configure.
Hibernate Configuration
Whats the name of Hibernate configuration file?
For Hibernate's configuration, we can use a simple hibernate.properties file, a slightly more sophisticated hibernate.cfg.xml file, or even complete programmatic setup. Most users prefer the XML configuration file:
Structure of Hibernate Configuration
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration3.0.dtd"> <hibernate-configuration> <session-factory>
</session-factory> </hibernate-configuration>
Structure of Hibernate Configuration
If you have several databases, use several <sessionfactory> configurations, usually in several configuration files (for easier startup). The dialect property element specifies the particular SQL variant Hibernate generates. The hbm2ddl.auto option turns on automatic generation of database schemas - directly into the database
Structure of Hibernate Configuration
Where should the configuration file placed? Copy the Hibernate configuration file into the source directory, so it will end up in the root of the classpath. Hibernate automatically looks for a file called hibernate.cfg.xml in the root of the classpath, on startup.
Hibernate Startup and Helper
Hibernate startup requires building a global SessionFactory object and to store it somewhere for easy access in application code. Well use a class that uses static singleton pattern.
Demo 1
Takeaway: Learn how to write a simple Hibernate Application
Hibernate_StartedApp
Object States
Detached
Persistent
GC
Transient
new
Object States
Transient - an object is transient if it has just been
instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned. Transient instances will be destroyed by the garbage collector if the application doesn't hold a reference anymore.
Object States
Persistent - a persistent instance has a representation in the database and an identifier value. It might just have been saved or loaded, however, it is by definition in the scope of a Session. Hibernate will detect any changes made to an object in persistent state and synchronize the state with the database when the unit of work completes.
Object States
Detached - a detached instance is an object that has been persistent, but its Session has been closed. A detached instance can be reattached to a new Session at a later point in time, making it (and all the modifications) persistent again.
How to make Objects Persistent
Newly instantiated instances of a a persistent class are considered transient by Hibernate. We can make a transient instance persistent by associating it with a session and calling save(). Long generatedId = (Long) sess.save(fritz);
How to Load Persistent Objects
The load() methods of Session gives you a way to retrieve a persistent instance if you already know its identifier. load() takes a class object and will load the state into a newly instantiated instance of that class, in persistent state. Example
Cat fritz = (Cat) sess.load(Cat.class, generatedId);
Note that load() will throw an ObjectNotFoundException if there is no matching database row
Loading persistent objects with get()
If you are not certain that a matching row exists, you should use the get() method, which hits the database immediately and returns null if there is no matching row. Example:
Cat cat = (Cat) sess.get(Cat.class, id);
if (cat==null) { cat = new Cat();
sess.save(cat, id);
} return cat;
Load() vs. get()
If you are not certain that a matching row exists, you should use the get() method, which hits the database immediately and returns null if there is no matching row. The load() method, on the other hand, will not hit the DB if the object in question can be found in the persistent context. Else, itll throw an ObjectNotFoundException.
Re-loading Objects
It is possible to re-load an object and all its collections at any time, using the refresh() method
Modifying persistent objects
Transactional persistent instances (ie. objects loaded, saved, created or queried by the Session) may be manipulated by the application and any changes to persistent state will be persisted when the Session is flushed There is no need to call a particular method (like update(), which has a different purpose) to make your modifications persistent.
Session Flushing
From time to time the Session will execute the SQL statements needed to synchronize the JDBC connection's state with the state of objects held in memory. This process, flush, occurs by default at the following points before some query executions from org.hibernate.Transaction.commit() from Session.flush()
Reattaching Detached Objects
Modifying an object after the session is closed has no effect on it's persistence state in the DB, the object is Detached; you can reattach a detached object to a new session by calling update() on the detached object
Deleting persistent objects
Session.delete() will remove an object's state from the database. Of course, your application might still hold a reference to a deleted object. It's best to think of delete() as making a persistent instance transient.
Demo 2
Takeaway: Learn how to deal with the persistent state of an object
Hibernate_ObjectPersistence
Object Equality
The problem stems from differences between object identity in the virtual machine (VM) and object identity in the database. From different parts of a concurrent running application, you might have two objects on the heap even though the object state is pulled from a single tuple in a DB.
Overriding equals() and hasCode()
Hibernate guarantees equivalence of persistent identity (database row) and Java identity only inside a particular session scope. So as soon as we mix instances retrieved in different sessions, we must implement equals() and hashCode() if we wish to have meaningful semantics
equals() Implementation
public boolean equals(Object other) {
if (this == other) return true; if ( !(other instanceof Person) ) return false; final Person aPerson = (Person) other; if ( !aPerson.getFirstName().equals( this.getFirstName() ) ) return false; if ( !aPerson.getLastName().equals( this.getLastName() ) ) return false; return true;
}
Key Generation
<id name="id" column="ID">
<generator class="assigned" />
</id> The optional <generator> child element names a Java class used to generate unique identifiers for instances of the persistent class. assigned is the default strategy which lets the application to assign an identifier to the object before save() is called
Takeaway: Learn how to write a basic Hibernate mapping file Hibernate_BasicMappings
Mapping Id Field
Use id element Use generator subelement with class attribute, which specifies the key generation scheme <class name="Person"> <id name="id" type="int"> <generator class="increment"/> </id> </class>
Key Generation Scheme via class attribute
class=increment
It generates identifiers of type long, short or int that are
unique only when no other process is inserting data into the same table. It should not the used in the clustered environment. class=assigned Lets the application to assign an identifier to the object before save() is called. This is the default strategy if no
<generator> element is specified.
class=native It picks identity, sequence or hilo depending upon the capabilities of the underlying database.
Takeaway: Learn how generate primary keys in DB table Hibernate_IdGeneration
Composite Key
For a table with composite key, you can multiple properties with the <composite-id> tag in the mapping file. The persistent class must implement the Serializable marker interface and override equals() and hashCode() methods.
Takeaway: Learn how generate composite keys Hibernate_CompositeKey
Hibernate DAO
DAO pattern Separation of data access (persistence) logic from business logic Enables easier replacement of database without affecting business logic DAO implementation strategies Domain DAO interface and implementation Domain DAO concrete classes
Takeaway: Learn how to segregate Database access code with DAO pattern Hibernate_DAO
Property Join
With Hibernate, you can move some properties to a different table using <join table> element. Using the <join> element, it is possible to map properties of one class to several tables.
Configuring a Connection Pool
Code Snippet
<property name="c3p0.min_size">5</property> <property name="c3p0.max_size">20</property> <property name="c3p0.timeout">1800</property> <property name="c3p0.max_statements">50</property>