Hibernate: Mapping Java Objects to Database Tables
Hibernate: Mapping Java Objects to Database Tables
Hibernate was written by Gavin King and open-sourced in 2001. Its premise: Java objects and relational tables are structurally different, and an ORM framework should handle the translation transparently — loading objects from rows, saving them back, managing relationships — so application code works with objects and never writes SQL.
After three years of JDBC DAOs and the entity bean disaster, Hibernate felt like the right abstraction.
The Mapping
In Hibernate 2.x, the mapping between classes and tables was defined in XML:
<!-- Device.hbm.xml -->
<hibernate-mapping>
<class name="com.nms.Device" table="devices">
<id name="ip" type="string" column="ip">
<generator class="assigned"/>
</id>
<property name="name" column="name" type="string"/>
<property name="status" column="status" type="string"/>
<set name="pollResults" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="device_ip"/>
<one-to-many class="com.nms.PollResult"/>
</set>
</class>
</hibernate-mapping>
The Java class was a plain JavaBean with no Hibernate dependencies:
public class Device {
private String ip;
private String name;
private String status;
private Set pollResults = new HashSet();
// getters and setters
public String getIp() { return ip; }
public void setIp(String ip) { this.ip = ip; }
// ...
}
No extends, no implements Remote, no lifecycle callbacks. A plain object. This was revolutionary after entity beans.
Session: Loading and Saving
// Configure Hibernate once at application startup
SessionFactory sf = new Configuration()
.configure("hibernate.cfg.xml")
.buildSessionFactory();
// Load a device
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Device device = (Device) session.get(Device.class, "192.168.1.1");
System.out.println(device.getName() + " is " + device.getStatus());
tx.commit();
session.close();
session.get generated SELECT ip, name, status FROM devices WHERE ip = ? behind the scenes. You never wrote that SQL.
Saving was equally simple:
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Device d = new Device();
d.setIp("192.168.1.50");
d.setName("new-switch");
d.setStatus("UNKNOWN");
session.save(d);
tx.commit(); // INSERT INTO devices ...
session.close();
Modifying a loaded object and committing the transaction automatically generated an UPDATE:
Device device = (Device) session.get(Device.class, "192.168.1.1");
device.setStatus("DOWN"); // dirty tracking
tx.commit(); // UPDATE devices SET status='DOWN' WHERE ip='192.168.1.1'
HQL: Hibernate Query Language
For queries, Hibernate provided HQL — a query language over the object model rather than the table:
List devices = session.createQuery(
"from Device d where d.status = :status order by d.ip")
.setParameter("status", "DOWN")
.list();
HQL was translated to SQL by Hibernate, which meant it was database-independent — the same HQL worked on MySQL, Oracle, and PostgreSQL.
For complex queries, Criteria API allowed programmatic query construction:
List devices = session.createCriteria(Device.class)
.add(Restrictions.eq("status", "DOWN"))
.addOrder(Order.asc("ip"))
.setMaxResults(100)
.list();
Lazy Loading: Power and Footgun
lazy="true" on the pollResults collection meant the results were not loaded until accessed. A query loading 500 devices did not also load their poll histories.
The footgun: accessing a lazy collection after the session closed threw LazyInitializationException. You had to ensure either the session was open when the collection was accessed (Open Session in View pattern) or the data was loaded eagerly within the transaction. This was the most common Hibernate bug in 2002.
What Hibernate Changed
Before Hibernate, every persistence operation required handwritten SQL, manual ResultSet mapping, and careful resource management. A DAO for a ten-column table was 200 lines of boilerplate.
After Hibernate: the mapping XML was perhaps 30 lines, the DAO perhaps 50. More importantly, changes to the object model were reflected in persistence automatically — adding a field required adding one line to the XML, not updating five methods.
The SQL was still there; Hibernate generated it. Understanding what SQL Hibernate was generating was essential for performance. The show_sql configuration flag printed every generated query — turning it on in development and checking the output became standard practice.
JPA (Java Persistence API, 2006) standardised the Hibernate model, and Hibernate 3 became a JPA provider. The annotations-based mapping in JPA eliminated the XML files. The core concept remained the same.