Hibernate is an Object Relational Mapping (ORM) tool. It manages the persistence of java objects in a relational database. The idea is that a programmer should be able to design his business objects as standard Java objects with very little interference from the problems of making these objects persist in a database. Together with a little help from the programmer, Hibernate saves the objects into the database, retrieves them when needed and supports queries on the database written in a form similar to SQL but which refers to objects and object properties instead of tables and column names. The end result is that the code that needs to be written to interact with the database is considerably shorter and simpler.

The Hibernate Object Life Cycle

Transient objects do not (yet) have any association with the database. they act like any normal Java object and are not saved to the database. When the last reference to a transient object is lost, the object itself is lost and is (eventually) garbage collected. There is no connection between transactions and such objects: commits and rollbacks have no effects on them. They can be turned into persistent objects via one of the save method calls if the Session object or by adding a reference from a persistent object to this object.

Persistent objects do have an association with the database. They are always associated with a persistence manager, i.e., a Session object and they always participate in a transaction. Actual updates of a database from the persistent object may occur at any time between when the object is updated to the end of the transaction: it does not necessarily happen immediately. However, this feature, which allows important optimizations in database interactions, is essentially invisible to the programmer. For example, one place where one might expect to notice the difference between the in-memory persistent object and the database version is at the point of executing a query. In such a case, Hibernate will, if necessary, synchronise any dirty objects with the database (i.e., save them) in order to ensure that the query returns the correct results.

A persistent object has a primary key value set, whether or not it has been actually saved to the database yet.

Calling the delete method of the Session object on a persistent object will cause its removal from the database and will make it transient.

Detached objects are objects that were persistent but no longer have a connection to a Session object (usually because you have closed the session). Such an object contains data that was synchronised with the database at the time that the session was closed, but, since then, the database may have changed; with the result that this object is now stale.

Important
A detached object may be re-attached later to another Session object to become persistent again. Thus, in essence, these objects can happily exist, and be used, without concern for being inside a transaction. This mechanism, in fact, is the basis for letting business objects which are stored persistently in the database, to escape up to higher levels in the system without having to add extra value beans (also known as Data Transfer Objects (DTOs) which exist to copy the data of objects tied to one layer in the system to objects tied to another layer. Without this mechanism, one typically has to create a number of classes for each business object, where the instance variables are all basically the same, but which differ in the layer specific details.

objectstates.png

The Hibernate Object Life Cycle

Given a pair of (persistent) objects of the same class, we now have three concepts of identity to consider.

a==b Java Identity
a.equals(b) Java Equality
a.getId().equals(b.getId()) Database Identity
The rule for Hibernate, is that if, within a single session, you request two objects which have the same database identifier, then you will get references to the same actual objects. However, if you reattach a object to a session, you have a potential source of confusion in that you could end up with two different persistent objects (different as defined by Java Equality), which should be stored in the same database row.

Since the programmer can define the meaning of Java Equality, it is important not to use the id field in that definition if the id field is a surrogate key. This is because Hibernate only sets the field when saving the object. Hence, for example, if you add the object to some set collection, then saving the object will result in its identity changing, and part of the rules about using the set collection class is that the contained object’s identity must not change while it is in the collection.

In fact, this situation is almost certain to occur because of the frequent use of collection classes to represent the many side of one-to-many or many-to-many relationships. Therefore we use the Java Equality concept to define when two objects should really be the same database object.

However, there are other problems with using all the non-id values of an object in the equality test: you really want the test to return true if the objects map to the same row of the the same table in the database (i.e. they represent the same real world concept). But two objects may represent the same real world object and have some different values. For example, two Customer objects may differ in the value of a password property (because the two objects date from different instances in time between which the customer has change her password). But they still refer to the same real world concept: i.e., the same customer.

The solution is to decide on a Business Key for a class. This is like a database key, but involves no generated surrogate keys. Instead it consists of those “real-world” properties of the class that the programmer considers to uniquely identify a particular record. It is not a requirement that the business key absolutely never changes, merely that it changes will not change within the period in which it might be stored in memory in a collection class. For the Customer class on a web application, an appropriate business key might be the customer’s email address. This, of course, can change, in which case the customer will be treated as a new different customer. However, this is rarely a significant problem, and if it is, one can always provide a mechanism to reconnect the old data about the customer to the new customer record. More importantly, from our point of view, a change of customer email address is extremely unlikely to affect any reattachment of a detached Customer object to a new session.

Note that Hibernate does not know or care anything about your business keys. As far as it is concerned, reattaching an object works by checking the id property of the object. If it is null, then the object is a new one that could be added to the database but certainly cannot be reattached. Otherwise, the object can be matched up with a record in the database and, on reattachment, the contents of the object are used to update the contents of the corresponding database record(s).

In writing an equals method, there are two important considerations to bear in mind:

If you write an equals method, you must write a hashCode method which always returns the same value for two objects which equals decides are equal.

When referring to instance variables of the argument object, always use the accessor method rather than the raw instance variable: this is because, in an environment such as a web application or service, you may actually be dealing with a proxy object rather than the actual object you expect for reasons of, for example, distributed load balancing or scalability to very large service loads.

Given that, the equals and hashCode methods should be written as follows:

public class Customer
{

public boolean equals(Object other)
{
if (this==other)
return true;
if (other==null)
return false;
if (!(other instanceof Customer))
return false;
final Customer o = (Customer) other;
return this.emailAddress.equals(o.getEmailAddress());
}

public int hashCode()
{
return emailAddress.hashCode();
}
}