Hibernate Notes
Hibernate Notes
⚡ Hibernate — Introduction
🎯 Goal
Understand why Hibernate is used and how it improves productivity compared to
plain JDBC.
🧩 Overview
When building a console-based application, Java + JDBC is usually enough.
For web or backend applications, you can use Servlets or frameworks like
Spring MVC (which internally rely on Servlets).
🧠 Key idea
Java is object-oriented, everything revolves around objects.
With plain JDBC, developers have to manually write SQL queries to bridge
these two worlds — converting objects into database rows and vice versa.
🚀 Why Hibernate?
Reduces manual SQL — no more writing all the INSERT , UPDATE , and SELECT
queries.
Bridges the gap between Java objects and database tables automatically.
Hibernate Notes 1
📝 In short: JDBC works fine, but Hibernate makes data handling faster, simpler,
and more developer-friendly through ORM.
🧩 What is Hibernate?
Hibernate is an ORM (Object Relational Mapping) framework.
ORM bridges the gap between Java objects and database tables, allowing
you to save, retrieve, and manage objects without writing SQL manually.
🧠 Why ORM?
Java is object-oriented — everything revolves around objects (data +
methods).
When using JDBC, developers must manually write SQL to insert, update, or
fetch data from tables.
This means:
💡 ORM frameworks like Hibernate solve this by automating the mapping between
objects and tables.
Hibernate Notes 2
🧩 How ORM Works
Hibernate looks at your class (blueprint) — e.g., Student class with rollNo , name ,
age .
Column types → matched with Java data types ( int → INTEGER , String → TEXT ,
etc.)
🚀 Benefits of Hibernate
No manual SQL: Hibernate handles CRUD operations automatically.
📝 In short:
Hibernate bridges Java objects and database tables seamlessly through ORM —
simplifying persistence, improving performance, and saving developers from
writing repetitive SQL.
Hibernate Notes 3
🎯(Step-by-Step)
Hibernate Practical Implementation
After understanding what Hibernate and ORM are, it’s time to implement
Hibernate in a real Java project 🚀
Here’s how I started:
🧱 1️⃣ Creating the Project
Opened IntelliJ IDEA (Community Edition) — the free version works perfectly
fine!
Searched → “postgresql”
Picked the second-last stable versions (always a safer bet than the latest
alpha/beta)
🔁 Reloaded the Maven project — and just like that, Hibernate and JPA
dependencies were added.
🧩 3️⃣ What’s Next
Now the project is set up and ready for configuration.
Hibernate Notes 4
⚡ Hibernate — Student Class, Session & Saving Data
🎯 Goal
Learn how to create a Java Student class, set up Hibernate sessions, and
understand the workflow for saving objects to a database.
Fields:
int rollNumber
String sName
int sAge
Generate:
Purpose: Holds student data that can later be saved to the database.
2. Set data:
[Link](101);
[Link]("Naveen");
[Link](30);
Goal is not just printing, but storing this data in Postgres database.
Hibernate Notes 5
🧩 Why Hibernate?
JDBC requires multiple steps to persist objects (manual SQL, connection
handling, transaction management).
🔮 Common Pitfalls
Directly calling [Link]() without initializing the session →
NullPointerException.
Database name
📝 Summary
Created a Student POJO with fields, getters, setters, and toString() .
Hibernate Notes 6
Direct object persistence requires proper configuration.
Next step: configure Hibernate with database details and successfully save
objects.
For XML:
You can use a different name, but then you must specify it in the configuration.
<property name="[Link].driver_class">[Link]</
property>
<property name="[Link]">jdbc:postgresql://localhost:543
2/yourDB</property>
Hibernate Notes 7
<property name="[Link]">postgres</property>
<property name="[Link]">0000</property>
Adjust driver, port, and credentials based on your database (Postgres, MySQL,
etc.).
🧩 Mapping Classes
Hibernate needs to know which classes are persistent.
Two options:
1. XML mapping
[Link]([Link]);
Steps:
Begin transaction:
Transaction tx = [Link]();
Save object:
[Link](student);
Commit transaction:
Hibernate Notes 8
[Link]();
<property name="[Link]">update</property>
Options:
Value Behavior
none Do nothing
update Create table if missing, update schema without removing old columns
✅ Result
After configuration, mapping, and transaction management:
📝 In short:
Hibernate allows automatic persistence of Java objects using XML or annotations,
manages transactions, and can create tables automatically — eliminating the need
to write SQL manually while keeping the code maintainable and database-
independent.
package [Link];
Hibernate Notes 9
import [Link];
import [Link];
import [Link];
// What is session factory and session? See, whenever you want to work
with the hibernate which deals with database.
// Hibernate says okay you are connecting with a database. And this is ac
tually a costly when you talk about the application,
// connecting with the database and doing some transactions. And to do t
hat you have to first open the session right. And to open the session you need
a session factory.
// first we have to get the object of configuration because this deals with t
he configuration.
// configuration, this knows that we have to find the configuration somew
here. And the way we do that is by using this method called [Link]
igure.
// So when you call this method this actually loads the XML.
Configuration cfg = new Configuration().configure();
// IMPORTANT: register your annotated entity
[Link]( [Link] );
// Then once we got the object of it we will use that configuration object t
o build a session factory.
SessionFactory sf = [Link]();
// this will return you the object of session factory using which we can cre
ate multiple sessions.
// So when you say open session it will create a new session. And we can
also use some existing session.
Session session = [Link]();
Hibernate Notes 10
So every time you save data it's a transaction
[Link]();
[Link]( student );
// And after transaction you have to commit the transaction. Otherwise thi
s will not save. So that means we have to commit it.
[Link]().commit();
[Link]();
[Link]( student );
}
}
<hibernate-configuration xmlns="[Link]
<session-factory>
<property name="[Link].driver_class">[Link]
ver</property>
<property name="[Link]">jdbc:postgresql://localhost:
5432/hibernatedemo</property>
<property name="[Link]">postgres</property>
<property name="[Link]">h@ppydays</proper
ty>
Hibernate Notes 11
</session-factory>
</hibernate-configuration>
package [Link];
import [Link];
import [Link];
@Entity
public class Student {
@Id
private int rollNo;
private String name;
private int age;
Hibernate Notes 12
public void setName(String name) {
[Link] = name;
}
@Override
public String toString() {
return "Student [rollNo=" + rollNo + ", name=" + name + ", age=" + age +
"]";
}
⚡SQLHibernate
Queries
— Storing Data and Viewing
🎯 Goal
Learn how to persist data with Hibernate, handle duplicate keys, and view SQL
queries in a readable format.
Hibernate Notes 13
Example flow:
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
Example output:
<property name="[Link]">[Link]
</property>
Not mandatory, but useful if Hibernate cannot automatically detect the DBMS.
🚀 Step-by-Step Example
1. Insert Student objects with unique rollNo .
Hibernate Notes 14
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="[Link]">[Link]
</property>
📝 In short:
Hibernate handles data persistence efficiently, automatically generates SQL
queries, and allows developers to view queries in readable formats while
maintaining database independence. Proper handling of primary keys and SQL
dialect ensures smooth operation.
⚡Fetching
Hibernate — Code Optimization &
Data
🎯 Goal
Learn how to refactor Hibernate code for efficiency, use modern APIs, manage
resources, and prepare for data retrieval.
Recommended replacement:
Hibernate Notes 15
[Link](student);
conventions.
Always close Session and SessionFactory after use to avoid memory leaks.
Options:
1. Try-with-resources:
1. Manual closing:
[Link]();
[Link]();
💡 Best practice: Always close what you open (like switching off unused lights).
3️⃣ Simplifying Configuration
Original code used multiple lines for configuration and building SessionFactory .
Benefits:
Fewer statements
Hibernate Notes 16
Easier to maintain
[Link](student);
[Link]();
[Link]();
Next steps:
📝 In short:
Refactor Hibernate code by replacing deprecated save() with persist() , simplify
configuration to one line, and always close Session and SessionFactory . This ensures
clean, efficient, and maintainable code while preparing for fetching data.
Hibernate Notes 17
⚡Handling
Hibernate — Fetching Data and
Nulls
🎯 Goal
Learn how to fetch data from the database using Hibernate 6, handle cases when
data is missing, and avoid deprecated methods.
🧩 Fetching Data
1️⃣ No Transaction Needed for Simple Reads
When fetching (reading) data, you don’t need a transaction.
Transactions are only required for manipulating the database (insert, update,
delete).
Notes:
Hibernate Notes 18
3️⃣ Handling Missing Data
If the record does not exist (e.g., PK = 9):
If used, it may return a proxy and can throw exceptions if the session is
closed.
📝 Summary:
For fetching data:
Hibernate Notes 19
Avoid deprecated methods like get() or load() .
⚡Operations
Hibernate — Update and Delete
🎯 Goal
Learn how to update and delete records using Hibernate 6+ with the modern, JPA-
aligned methods merge() and remove() .
🧩 CRUD Recap
Hibernate supports the four core database operations — Create, Read, Update,
and Delete — collectively known as CRUD.
Hibernate Requires
Operation Deprecated Replacement
Method Transaction
✅ Example
Hibernate Notes 20
Transaction tx = [Link]();
[Link](student);
[Link]();
To delete, Hibernate needs the entity object, not just the ID.
✅ Example
Transaction tx = [Link]();
Hibernate Notes 21
[Link]();
🔍 Hibernate Logs
Hibernate: select s1_0.rollNo, s1_0.age, s1_0.name from Student s1_0 where s1_
[Link]=?
Hibernate: delete from Student where rollNo=?
💡 You must fetch before removing if you only have the primary key.
⚙️ Best Practices
Always start a transaction for merge() or remove() .
Handle nulls safely — find() may return null if record doesn’t exist.
Transaction tx = [Link]();
// Update example
Student s1 = new Student(103, "Harsh", 23);
[Link](s1);
// Delete example
Student s2 = [Link]([Link], 109);
[Link](s2);
[Link]();
[Link]();
[Link]();
Hibernate Notes 22
📝 In short:
Hibernate’s modern API replaces old methods with JPA-friendly ones — use
for updates and inserts, and remove() for deletions. Always use transactions
merge()
Class name → becomes the entity name → becomes the table name.
Annotations let you override those defaults without renaming your Java
classes/fields.
@Table(name = "Alien_Table")
Overrides the table name for the entity (does not change the Java class
name or the entity name).
@Id
Marks the primary-key field for the entity (required — every entity must
have an @Id ).
Hibernate Notes 23
@Column(name = "alienName_column")
Overrides the column name for a field (so the Java field alienName can map
to alienName_column in DB).
@Transient
Prevents a field from being persisted to the database (useful for fields
used only in-memory or for processing).
@Entity + @Id on alienId → marks the class as an entity with primary key.
on techStack →
@Transient techStack is not created as a column; it stays in the
Java object only.
[Link] modes:
→ drops and recreates the table every run (good for clean dev runs;
create
update → creates the table if missing and adjusts schema if possible (safer
for iterative dev).
Demo used create to show fresh table creation, and update to preserve/alter
existing tables.
@Entity(name = "alien_entity")
@Table(name = "Alien_Table")
@Column(name = "alienName_column")
Skip a field:
@Transient
Hibernate Notes 24
✅ Practical takeaways
Use @Entity + @Id to make a class persistent.
Use @Table and @Column when you need DB-friendly names (snake_case,
legacy schemas).
Use @Transient for fields that should stay only in the object, not the DB.
📝 In short:
Annotations give precise control over how your Java classes map to database
tables and columns—use them to match DB naming conventions, omit transient
data, and make schema behavior predictable during development.
⚡types
Hibernate — Embeddables / Complex
🎯 Goal
Show how to store a complex value object (not a separate entity/table) inside an
entity using Hibernate’s @Embeddable — e.g., embedding a Laptop object inside an
Alien record so laptop fields become columns on the same table.
Custom classes (e.g. Laptop ) are not automatically mappable — Hibernate can’t
determine a JDBC type and you get an error like:
Hibernate Notes 25
could not determine recommended JDBC type
You don’t want a separate table for Laptop — you want the Laptop fields to
become columns on the Alien table.
3. In the Alien entity, replace the simple field (or @Transient ) with a reference:
4. Persist an Alien whose laptop is a Laptop instance. Hibernate will map the Laptop
After @Embeddable — Hibernate creates columns for the Laptop fields on the Alien
Hibernate Notes 26
Fetching via [Link]([Link], 1) printed the Alien (with Laptop ), but the demo
noted the select/query behavior (why a SELECT wasn’t issued in that run) —
that will be explained in a later video.
@Embeddable
public class Laptop {
private String brand;
private String model;
private double price;
private String color;
// getters/setters, toString
}
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
private Laptop laptop; // embedded complex type
// getters/setters, toString
}
[Link]();
[Link](a1);
[Link]().commit();
Hibernate Notes 27
Alien a2 = [Link]([Link], 1);
[Link](a2);
✅ Practical takeaways
Use @Embeddable for value objects you want flattened into the same table
(address, laptop, money, etc.).
If Hibernate can’t infer a JDBC type for a field, consider @Embeddable for
composite/value types.
📝 In short:
@Embeddablelets you model complex value objects inside entities so their fields
become regular columns on the owning entity’s table — keeping domain structure
in Java without extra tables.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
Hibernate Notes 28
[Link](l1);
[Link]();
[Link]();
[Link](a1);
}
}
package [Link];
import [Link].*;
Hibernate Notes 29
// primary key (alienId)
// )
@Entity
// @Table(name = "Alien_Table")
public class Alien {
@Id
private int alienId;
// Changing the column name
// table Alien_Table (
// alienId integer not null,
// alienName_column varchar(255),
// techStack varchar(255),
// primary key (alienId)
// )
//Hibernate:
// insert
// into
// Alien_Table
// (alienName_column, techStack, alienId)
// values
// (?, ?, ?)
// @Column(name = "alienName_column")
private String alienName;
Hibernate Notes 30
// into
// Alien_Table
// (alienName_column, alienId)
// values
// (?, ?)
//Alien{alienId=1, alienName='Sai Mahendra Penumakula', techStack='Java'}
// @Transient
private String techStack;
// this is a complex type. This is a reference variable here Laptop. Not a sim
ple type like int string.
// In this Alien we are saying entity here because the hibernate should know
about alien. In Laptop we are not putting anything on the top here.
// So how it will work now? We don't want to put entity here because it will c
reate its own table. I don't want to have its own table.
// What I want is I want a table structure, something like this where you have
ID, we got a id, name, techStack But for laptop, I don't want a single field.
// I want the laptop fields as three different fields in the same table. Now, wh
at we're trying to do is we are trying to embed the laptop details inside the alie
n.
private Laptop laptop;
Hibernate Notes 31
}
@Override
public String toString() {
return "Alien{" +
"alienId=" + alienId +
", alienName='" + alienName + '\'' +
", techStack='" + techStack + '\'' +
", laptop=" + laptop +
'}';
}
// Hibernate:
// set client_min_messages = WARNING
//Hibernate:
// drop table if exists Alien cascade
//Hibernate:
// create table Alien (
// alienId integer not null,
// price float(53),
// alienName varchar(255),
// brand varchar(255),
// color varchar(255),
// model varchar(255),
// techStack varchar(255),
// primary key (alienId)
// )
Hibernate Notes 32
//Hibernate:
// insert
// into
// Alien
// (alienName, brand, color, model, price, techStack, alienId)
// values
// (?, ?, ?, ?, ?, ?, ?)
//Alien{alienId=1, alienName='Sai Mahendra Penumakula', techStack='Java',
laptop=Laptop{brand='Apple', model='Macbook Pro', price=2200.0, color='Gr
ey'}}
}
package [Link];
import [Link];
@Embeddable
public class Laptop {
Hibernate Notes 33
public void setModel(String model) {
[Link] = model;
}
@Override
public String toString() {
return "Laptop{" +
"brand='" + brand + '\'' +
", model='" + model + '\'' +
", price=" + price +
", color='" + color + '\'' +
'}';
}
}
⚡OneToMany,
Hibernate — Associations: OneToOne,
ManyToOne, ManyToMany
🎯 Goal
Hibernate Notes 34
Understand how to model relationships between entities in Hibernate — when to
keep a value as an embeddable, when to make it a separate entity, and the basic
mapping options for OneToOne, OneToMany / ManyToOne, and ManyToMany.
🧩story)
Why we need relationships (the laptop → alien
An embeddable (like Laptop inside Alien ) is fine when laptop is just a value
object flattened into the Alien table.
Laptop may need its own primary key (it is a first-class entity).
You can represent the link by adding a foreign key column on one side.
Result: each alien has one laptop; each laptop belongs to one alien.
Schema idea
2) One-to-Many / Many-to-One
One Alien → Many Laptop (from alien perspective: OneToMany).
Typical modeling: put the foreign key in the child table (Laptop), since laptops
belong to one alien.
Hibernate Notes 35
An alien may have multiple laptops (101,102,103…). Storing multiple laptop IDs
in an Alien column doesn’t work.
Instead, add alienId FK in Laptop so each laptop row points to its owner.
Schema idea
That third table records which alien has which laptop (useful for flexible
mappings or when neither side should own the FK).
Alien(alienId, ...)
Laptop(laptopId, ...)
Alien_Laptop(alienId, laptopId) <-- mapping table rows for associations
4) Many-to-Many
Use when many aliens can be associated with many laptops (e.g., shared lab
laptops).
Requires a third table (join table) that holds pairs (alienId, laptopId).
Demo note: direct ManyToMany will create that third table automatically, but the
transcript warns there are caveats and it “won’t work the way you want” in all
cases — practical details are covered in the implementation video.
Schema idea
Alien(alienId, ...)
Laptop(laptopId, ...)
Alien_Laptop(alienId, laptopId) <-- many-to-many join table
Put the foreign key on the child table (Laptop) for OneToMany / ManyToOne
— it models “many belong to one” naturally.
Use a join table when you don’t want a FK on either main table or when
modeling many-to-many associations.
📝 In short:
Choose embeddable for simple value objects. Choose separate entities + FK or
join table for relationships that require identity or multiplicity. OneToOne,
OneToMany/ManyToOne, and ManyToMany are the basic shapes — the mapping
choice (FK in child vs. join table) depends on ownership and multiplicity.
entities.
🧩 What we changed
Laptop— converted from an embeddable/value object to a full entity with its
own primary key ( laptopId ) and @Entity .
Alien — now contains a Laptop reference (an entity field), annotated @OneToOne .
Hibernate Notes 37
We persist both Laptop and Alien (order: laptop first, then alien) so foreign-key
references exist.
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
// getters/setters, toString
}
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
@OneToOne(cascade = [Link])
private Laptop laptop;
// getters/setters, toString
}
Persisting in main :
Hibernate Notes 38
.buildSessionFactory();
[Link]();
[Link]();
[Link]();
Create Alien table (with a unique FK column for laptop to enforce 1:1).
Verifying: pgAdmin shows laptop row and alien row; the alien row contains the
laptopId reference.
Persisting both entities (or using cascade ) ensures related rows are saved;
demo used [Link] on the @OneToOne so persist(alien) could persist laptop
— demo showed persisting laptop explicitly then alien.
The demo persisted laptop first, then alien — that’s a clear, explicit order to
avoid FK problems.
The @OneToOne mapping created a unique FK in the owner table so one alien →
one laptop and vice versa.
Hibernate Notes 39
✅ Practical takeaway
Use a separate entity when the related object needs identity or its own
lifecycle (e.g., Laptop ).
For a strict one-to-one, put the foreign key on the owning side (here Alien ) and
annotate the field with @OneToOne .
📝 In short:
To model a real one-to-one relation, make the sub-object an entity, annotate the
reference with @OneToOne (optionally cascade ), persist the entities (laptop then alien
or use cascade), and Hibernate will create the FK and handle inserts for you.
package org.hibernate_one_to_one_mapping;
import [Link];
import [Link];
import [Link];
import [Link];
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
@OneToOne(cascade = [Link])
private Laptop laptop;
Hibernate Notes 40
}
@Override
public String toString() {
return "Alien{" +
"alienId=" + alienId +
", alienName='" + alienName + '\'' +
", techStack='" + techStack + '\'' +
", laptop=" + laptop +
'}';
Hibernate Notes 41
}
}
package org.hibernate_one_to_one_mapping;
import [Link];
import [Link];
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
Hibernate Notes 42
public void setModel(String model) {
[Link] = model;
}
@Override
public String toString() {
return "Laptop{" +
"laptopId=" + laptopId +
", brand='" + brand + '\'' +
", model='" + model + '\'' +
", price=" + price +
", color='" + color + '\'' +
'}';
}
}
<hibernate-configuration xmlns="[Link]
<session-factory>
<property name="[Link].driver_class">[Link]
ver</property>
Hibernate Notes 43
<property name="[Link]">jdbc:postgresql://localhost:
5432/hibernatedemo</property>
<property name="[Link]">postgres</property>
<property name="[Link]">h@ppydays</proper
ty>
<property name="[Link]">create</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="[Link]">[Link]
alect</property>
</session-factory>
</hibernate-configuration>
package org.hibernate_one_to_one_mapping;
import [Link];
import [Link];
import [Link];
import [Link];
Hibernate Notes 44
// Configuration cfg = new Configuration().configure();
// // IMPORTANT: register your annotated entity
// [Link]( [Link] );
// [Link]( [Link] );
SessionFactory sf = new Configuration().addAnnotatedClass([Link]).
addAnnotatedClass([Link]).configure().buildSessionFactory();
[Link]();
[Link]();
[Link](a1);
}
}
Hibernate Notes 45
If you naively annotate only the parent ( @OneToMany on Alien ) Hibernate may
create a join table to store the associations.
A join table is fine sometimes, but often you want the FK column on the child
table (no extra join table) — i.e., the child ( Laptop ) holds the foreign key to the
parent ( Alien ).
That join table contains two columns (alienId, laptopId); their combination acts
as a composite key.
Result: no join table; Laptop gets an alien_id FK column, and each laptop row
references the owning alien.
Persisted the laptops and the alien (demo persisted laptops explicitly then
alien).
When mappedBy was missing, Hibernate created a join table that stored pairs
(alienId, laptopId) (composite uniqueness).
Hibernate Notes 46
After adding mappedBy = "alien" on the Alien side and annotating Laptop with
@ManyToOne , Hibernate did not create a join table — Laptop table got the alien FK
column instead.
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
@OneToMany(mappedBy = "alien")
private List<Laptop> laptops;
// getters/setters, toString
}
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
@ManyToOne
private Alien alien; // owning side: stores the FK
// getters/setters, toString
}
Hibernate Notes 47
[Link](a1); [Link](a1); [Link](a1);
[Link]([Link](l1,l2,l3));
[Link](l1);
[Link](l2);
[Link](l3);
[Link](a1);
[Link]();
If you leave the mapping unowned on either side, Hibernate will create a join
table for the association.
When using bidirectional mappings, set both sides in code (set [Link] and
[Link]) so the in-memory model and DB stay consistent.
Persist order in the demo: laptops then alien — explicit persists or cascade can
automate this; demo persisted children then parent.
The join table columns together behave like a composite key (unique
combination) — that's why duplicates are not stored.
📝 In short:
To model one alien → many laptops, annotate the parent with
@OneToMany(mappedBy="...") and the child with @ManyToOne . Let the child be the owning
side (FK column lives on child). If you skip mappedBy , Hibernate will create a join
table to track the association.
Hibernate Notes 48
package org.hibernate_onetomany_manytoone;
import [Link];
import [Link];
import [Link];
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
Hibernate Notes 49
return model;
}
@Override
public String toString() {
return "Laptop{" +
"laptopId=" + laptopId +
", brand='" + brand + '\'' +
", model='" + model + '\'' +
", price=" + price +
", color='" + color + '\'' +
'}';
Hibernate Notes 50
}
}
package org.hibernate_onetomany_manytoone;
import [Link].*;
import [Link];
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
// One Alien can have multiple laptops so that's why we have created Lapto
p reference in Alien class which is one to many relation
// alien, says i have written one to many, so it is my job to create separate ta
ble which will maintain this records.
// Laptop says since you are saying that alien even I'm maintaining it. So you
are maintaining those record two times which causes redundancy
// @OneToMany
// private List<Laptop> laptops;
// what we can do to skip the redundancy or extra table creation , we can use
mapped by we're saying who is mapping it.
// It is a responsibility of the laptop class in this with the alien variable.
@OneToMany(mappedBy = "alien")
private List<Laptop> laptops;
Hibernate Notes 51
}
@Override
public String toString() {
return "Alien{" +
"alienId=" + alienId +
", alienName='" + alienName + '\'' +
", techStack='" + techStack + '\'' +
", laptop=" + laptops +
'}';
}
}
package org.hibernate_onetomany_manytoone;
Hibernate Notes 52
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
Hibernate Notes 53
ich Many to One - Many Laptops belong to one alien
[Link](a1);
[Link](a1);
[Link](a1);
}
}
⚡ Hibernate — ManyToMany
🎯 Goal
Show how to model a many-to-many relationship in Hibernate — e.g., one Alien
can be linked to many Laptop objects and one Laptop can be linked to many Alien
Hibernate Notes 54
objects — and how to control which side owns the association so Hibernate
creates a single join table.
If both entities are annotated as owners (i.e., both think they should map the
relation), Hibernate may create two mapping tables (duplicate mapping). You
must choose one owning side to avoid redundant join tables.
@ManyToMany
private List<Laptop> laptops;
3. Make the other side the inverse (mapped) side to avoid duplicate mapping:
@ManyToMany(mappedBy = "laptops")
private List<Alien> aliens;
Hibernate Notes 55
a1 → laptops l1, l2
a2 → laptops l2, l3
a3 → laptops l1
Set corresponding aliens lists on each Laptop so both sides reflect the relation.
When was not set, Hibernate created two join tables ( alien_laptop and
mappedBy
After adding mappedBy = "laptops" on the Laptop side, Hibernate created only one
join table (e.g., alien_laptops ) and used it to store the (alienId, laptopId) pairs.
The join table records exactly the mapping described (101→l1,l2; 102→l2,l3;
103→l1).
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
@ManyToMany
private List<Laptop> laptops;
// getters/setters
}
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
// ...
Hibernate Notes 56
@ManyToMany(mappedBy = "laptops")
private List<Alien> aliens;
// getters/setters
}
[Link]([Link](l1, l2));
[Link]([Link](l2, l3));
[Link]([Link](l1));
[Link]([Link](a1, a3));
[Link]([Link](a1, a2));
[Link]([Link](a2));
[Link](l1);
[Link](l2);
[Link](l3);
[Link](a1);
[Link](a2);
[Link](a3);
[Link]();
Pick an owning side — use mappedBy on the other side to prevent duplicate join
tables.
Keep both sides in sync in code (set [Link] and [Link]) so the
object graph is consistent before persisting.
Use [Link] for single-element lists (demo used both [Link] and [Link] ).
one join table — pairs of alien & laptop IDs (the association)
Hibernate Notes 57
If you see two join tables, that means both sides were treated as owners —
add mappedBy to one side to fix it.
📝 In short:
Model many-to-many in Hibernate with @ManyToMany on both sides, but declare
only one owning side and use mappedBy on the inverse side. Populate both sides in
memory, persist entities, and Hibernate will maintain a single join table holding the
associations.
package org.hibernate_many_to_many;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
@ManyToMany
private List<Laptop> laptops;
Hibernate Notes 58
return alienName;
}
@Override
public String toString() {
return "Alien{" +
"alienId=" + alienId +
", alienName='" + alienName + '\'' +
", techStack='" + techStack + '\'' +
", laptop=" + laptops +
'}';
}
}
package org.hibernate_many_to_many;
import [Link];
import [Link];
Hibernate Notes 59
import [Link];
import [Link];
import [Link];
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
@ManyToMany(mappedBy = "laptops")
private List<Alien> aliens;
Hibernate Notes 60
public String getColor() {
return color;
}
@Override
public String toString() {
return "Laptop{" +
"laptopId=" + laptopId +
", brand='" + brand + '\'' +
", model='" + model + '\'' +
", price=" + price +
", color='" + color + '\'' +
'}';
}
}
Hibernate Notes 61
package org.hibernate_many_to_many;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
Hibernate Notes 62
[Link]("Java");
[Link]([Link](l1, l2));
[Link]([Link](l2, l3));
// [Link]([Link](l1));
// As we are holding one value prefer to use [Link]
[Link]([Link](l1));
Hibernate Notes 63
[Link](a2);
[Link](a3);
[Link]();
}
}
After persisting data, a [Link]([Link], id) did not immediately issue SQL that
loads the Laptop collection.
Why? Hibernate returned the Alien from the same session (L1 cache) and used
lazy fetching for the collection — laptops are loaded only when accessed.
Opening a new session and calling find forced Hibernate to query the
database (L1 cache scope is per-session).
Hibernate Notes 64
🧠 Key concepts from the demo
Level-1 cache (L1) — default per-session cache. If you persist and then find in
the same session, Hibernate reads from the session cache and may not issue
a SELECT .
Level-2 cache (L2) — shared across sessions (not enabled automatically). The
demo mentions libraries like ehcache or caffeine if you want cross-session
caching.
Default for collections — LAZY: collections (e.g., @OneToMany lists) are fetched
lazily by default to avoid expensive unnecessary loads.
EAGER fetch — forces Hibernate to load the collection along with the owner
(can produce joins and bigger result sets).
Hibernate Notes 65
Session session1 = [Link]();
Alien a3 = [Link]([Link], 1); // issues SELECT
@OneToMany(fetch = [Link])
private List<Laptop> laptops;
Observed SQL when eager: Hibernate does a join and fetches both Alien and
Laptop columns in one query.
⚖️ Pros / Cons
Lazy (default for collections)
Pros: avoids expensive loads when you don’t need associated data; better
for large collections.
Cons: may trigger additional queries later (N+1 risk unless careful).
Eager
Hibernate Notes 66
Pros: convenient when you always need the association right away.
Cons: can produce heavy joins and poor performance for large collections
— generally not recommended for big or optional collections.
To see what Hibernate SQL is doing, inspect the console output (set
hibernate.show_sql / format_sql as in earlier demos).
Use [Link] only when you are sure the collection is always needed and
small.
📝 In short:
Hibernate defaults to lazy for collections (efficient), uses a per-session L1 cache
(so reads in the same session may not hit DB), and supports eager fetching when
you really want the association loaded immediately — but eager can be costly for
large collections. Use L2 caching if you need cross-session caching (extra libs
required).
package org.hibernate_eager_lazy_demo;
import [Link].*;
import [Link];
@Entity
public class Alien {
@Id
Hibernate Notes 67
private int alienId;
private String alienName;
private String techStack;
@OneToMany
private List<Laptop> laptops;
Hibernate Notes 68
public void setLaptops(List<Laptop> laptops) {
[Link] = laptops;
}
@Override
public String toString() {
return "Alien{" +
"alienId=" + alienId +
", alienName='" + alienName + '\'' +
", techStack='" + techStack + '\'' +
", laptop=" + laptops +
'}';
}
package org.hibernate_eager_lazy_demo;
import [Link].*;
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
Hibernate Notes 69
}
@Override
public String toString() {
return "Laptop{" +
"laptopId=" + laptopId +
", brand='" + brand + '\'' +
", model='" + model + '\'' +
Hibernate Notes 70
", price=" + price +
", color='" + color + '\'' +
'}';
}
}
package org.hibernate_eager_lazy_demo;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
Hibernate Notes 71
[Link]("HP");
[Link]("HP Notebook");
[Link](1900.00);
[Link]("Silver");
[Link]([Link](l1, l2));
[Link]([Link](l3));
/*
Hibernate Notes 72
ewkx61nxv2istb3i8hxoqg
Hibernate: alter table if exists Alien_Laptop drop constraint if exists FKf54
7h580b705l8y4fhb73hk9g
Hibernate: drop table if exists Alien cascade
Hibernate: drop table if exists Alien_Laptop cascade
Hibernate: drop table if exists Laptop cascade
Hibernate: create table Alien (alienId integer not null, alienName varchar
(255), techStack varchar(255), primary key (alienId))
Hibernate: create table Alien_Laptop (Alien_alienId integer not null, laptop
s_laptopId integer not null unique)
Hibernate: create table Laptop (laptopId integer not null, price float(53) n
ot null, brand varchar(255), color varchar(255), model varchar(255), primary k
ey (laptopId))
Hibernate: alter table if exists Alien_Laptop add constraint FKd19ewkx61n
xv2istb3i8hxoqg foreign key (laptops_laptopId) references Laptop
Hibernate: alter table if exists Alien_Laptop add constraint FKf547h580b7
05l8y4fhb73hk9g foreign key (Alien_alienId) references Alien
Hibernate: insert into Laptop (brand,color,model,price,laptopId) values
(?,?,?,?,?)
Hibernate: insert into Laptop (brand,color,model,price,laptopId) values
(?,?,?,?,?)
Hibernate: insert into Laptop (brand,color,model,price,laptopId) values
(?,?,?,?,?)
Hibernate: insert into Alien (alienName,techStack,alienId) values (?,?,?)
Hibernate: insert into Alien (alienName,techStack,alienId) values (?,?,?)
Hibernate: insert into Alien_Laptop (Alien_alienId,laptops_laptopId) values
(?,?)
Hibernate: insert into Alien_Laptop (Alien_alienId,laptops_laptopId) values
(?,?)
Hibernate: insert into Alien_Laptop (Alien_alienId,laptops_laptopId) values
(?,?)
*/
// And now when you see the query and it is not firing the select query. S
o what's wrong here? It is basically using a concept of cache.
// So in hibernate it provides you a concept of cache which we don't get
by default in JDBC. That's one of the advantage of using hibernate.
// So we got two different levels of cache level one cache and level two c
ache.
Hibernate Notes 73
// in the same session. When you are doing this it will not fire the query to
the database. It will basically check from the same session. And that's what is
happening here.
/*
Hibernate: set client_min_messages = WARNING
Hibernate: alter table if exists Alien_Laptop drop constraint if exists FKd19
ewkx61nxv2istb3i8hxoqg
Hibernate: alter table if exists Alien_Laptop drop constraint if exists FKf54
7h580b705l8y4fhb73hk9g
Hibernate: drop table if exists Alien cascade
Hibernate: drop table if exists Alien_Laptop cascade
Hibernate: drop table if exists Laptop cascade
Hibernate: create table Alien (alienId integer not null, alienName varchar
(255), techStack varchar(255), primary key (alienId))
Hibernate: create table Alien_Laptop (Alien_alienId integer not null, laptop
s_laptopId integer not null unique)
Hibernate: create table Laptop (laptopId integer not null, price float(53) n
ot null, brand varchar(255), color varchar(255), model varchar(255), primary k
ey (laptopId))
Hibernate: alter table if exists Alien_Laptop add constraint FKd19ewkx61n
xv2istb3i8hxoqg foreign key (laptops_laptopId) references Laptop
Hibernate: alter table if exists Alien_Laptop add constraint FKf547h580b7
05l8y4fhb73hk9g foreign key (Alien_alienId) references Alien
Hibernate: insert into Laptop (brand,color,model,price,laptopId) values
(?,?,?,?,?)
Hibernate: insert into Laptop (brand,color,model,price,laptopId) values
(?,?,?,?,?)
Hibernate: insert into Laptop (brand,color,model,price,laptopId) values
(?,?,?,?,?)
Hibernate: insert into Alien (alienName,techStack,alienId) values (?,?,?)
Hibernate: insert into Alien (alienName,techStack,alienId) values (?,?,?)
Hibernate Notes 74
Hibernate: insert into Alien_Laptop (Alien_alienId,laptops_laptopId) values
(?,?)
Hibernate: insert into Alien_Laptop (Alien_alienId,laptops_laptopId) values
(?,?)
Hibernate: insert into Alien_Laptop (Alien_alienId,laptops_laptopId) values
(?,?)
Hibernate: select a1_0.alienId,a1_0.alienName,a1_0.techStack from Alien a1
_0 where a1_0.alienId=?
*/
// Maybe we have this intention that multiple sessions should share the sa
me data if they have.
// In that case you have to use second level cache with the help of some li
braries like ehcache or caffeine.
// But level one cache by default you will get from hibernate.
// But if we look at the fetch when we say get I want alien, I'm expecting t
hat I will get everything from the alien.
// I will get the ID name, uh, what else we have? And also I want the detail
s of a laptop. But if we look at the query which is just firing -select a1_0.alienId,
a1_0.alienName,a1_0.techStack from Alien a1_0 where a1_0.alienId=?
// It is not fetching the laptop. The reason it is doing because By default,
when you have a collection in a entity, it basically uses something called a laz
y fetch.
// So by default it is implementing lazy fetch. But if we asks then only it wi
ll fetch the laptop as well. I am asking it t print this time it fetches
// Hibernate: select l1_0.Alien_alienId,l1_1.laptopId,l1_1.brand,l1_1.color,l1_1.m
odel,l1_1.price from Alien_Laptop l1_0 join Laptop l1_1 on l1_1.laptopId=l1_0.lapto
ps_laptopId where l1_0.Alien_alienId=?
// Alien{alienId=1, alienName='Sai Mahendra Penumakula', techStack='Jav
a', laptop=[Laptop{laptopId=1, brand='Apple', model='Macbook Pro', price=22
00.0, color='Grey'},
// Laptop{laptopId=2, brand='Dell', model='Dell XPS', price=1800.0, color
='Black'}]}
// The reason it is doing lazy is what if we have huge amount of data and
you don't even need it? Then simply by firing
// a get or by calling a get method, it is fetching everything from the table
Hibernate Notes 75
[Link] will be expensive and that's why it says only when you need it.
// But what if you don't want lazy, what you want eager? In that case we c
an put a property. Even if we don't ask it will fetch the laptop details
// @OneToMany(fetch = [Link])
// private List<Laptop> laptops;
// Hibernate: select a1_0.alienId,a1_0.alienName,a1_0.techStack,l1_0.Alien_
alienId,l1_1.laptopId,l1_1.brand,l1_1.color,l1_1.model,l1_1.price
// from Alien a1_0 left join Alien_Laptop l1_0 on a1_0.alienId=l1_0.Alien_alie
nId left join Laptop l1_1 on l1_1.laptopId=l1_0.laptops_laptopId where a1_0.alienId
=?
[Link]();
[Link]();
}
}
🧩 Context
In the previous demo (Lazy vs Eager fetching), Hibernate avoided firing a second
SQL query for the same entity when retrieved in the same session.
Hibernate Notes 76
⚙️ Caching Flow (Conceptually)
Imagine a 3-tier setup:
2. Hibernate sends a SQL query to fetch Alien 101 from the database.
Enabled by
default
✅ Always on
Stored in Hibernate’s internal session memory
When used Automatically used for any entity loaded or persisted in the session
Two find() calls for the same entity in one session → only first fires
Example Behavior
SQL
Example:
Hibernate Notes 77
// 2nd fetch — comes from L1 cache, no DB hit
Alien alien2 = [Link]([Link], 101);
Enabled by
default
❌ Requires configuration
Purpose Share cached data between multiple sessions
Example If Session 1 fetches Alien 101, and Session 2 requests it — Hibernate can
Behavior serve it from shared cache instead of hitting DB again
Conceptual Example:
⚠️ Risks:
May serve stale data if the DB changed between cache reads.
Hibernate Notes 78
Needs careful invalidation and synchronization logic.
2. Configure it in [Link] :
<property name="[Link].use_second_level_cache">true</prope
rty>
<property name="[Link].factory_class">
[Link]
</property>
3. Annotate entities:
@Cacheable
@[Link](usage = CacheConcurrencyStrategy.R
EAD_WRITE)
public class Alien { ... }
💡 Key Takeaways
L1 cache = per session (default, always on).
Prevents duplicate DB queries within the same session.
📝 In short:
Hibernate’s L1 cache is automatic and session-scoped — it saves you from
repeated DB hits within the same session.
Hibernate Notes 79
Caching boosts performance but must be used carefully to avoid stale data or
unnecessary complexity.
🧩 Context
In traditional database systems like MySQL, PostgreSQL, or Oracle, we use SQL
(Structured Query Language) to perform CRUD operations — Create, Read,
Update, Delete — directly on tables and columns.
However, Hibernate abstracts the database using entities (Java classes mapped
to tables).
Instead of thinking in terms of tables and rows, we think in terms of objects and
their properties.
That’s where HQL comes in — a query language built on top of SQL concepts but
designed for objects.
⚙️ What is HQL?
HQL (Hibernate Query Language) is an object-oriented dialect of SQL.
Hibernate Notes 80
In short:
👉 SQL talks to the database schema.
👉 HQL talks to the Java entity model.
🧠 Basic Query Examples
Goal SQL Query Equivalent HQL Query
💡 Notice:
No need to use SELECT * in HQL when you want the entire object — Hibernate
automatically maps properties to entity fields.
🧩 Example in Java
Session session = [Link]();
Transaction tx = [Link]();
[Link]();
[Link]();
Hibernate Notes 81
⚡ Why HQL Instead of SQL?
Advantage Description
Object-oriented You query entities and fields, not tables and columns.
But for portability and cleaner code, prefer HQL whenever possible.
💡 Key Takeaways
HQL ≠ SQL — it’s object-oriented and works with entities.
You can write HQL almost like SQL, but refer to class names and field names
instead of tables and columns.
📝 In short:
HQL lets you query objects, not tables.
Hibernate Notes 82
⚡Language)
Hibernate — HQL (Hibernate Query
🎯 Goal
Understand what HQL (Hibernate Query Language) is, how it differs from SQL,
and how to use it in Java to query entities (objects) instead of database tables.
🧩 What is HQL?
HQL = Hibernate Query Language — an object-oriented query language built
on SQL concepts.
Hibernate converts HQL into SQL behind the scenes and returns objects rather
than raw ResultSet rows.
Cleaner API in Java: you get typed objects/lists directly from queries.
HQL (entity-focused)
Notes:
Hibernate Notes 83
In HQL you usually write FROM EntityName — no SELECT * needed when
fetching entire entities.
Use entity class names and property names (not table/column names).
The createQuery(...) call returns a Query object; use getResultList() to execute and
obtain a List of entities.
You can filter results with WHERE on entity properties (e.g., where ram = 32 ).
HQL is derived from SQL — if you know SQL, HQL is straightforward (replace
table/column names with entity/property names).
Hibernate Notes 84
List<Laptop> list = [Link]();
Use native queries sparingly — HQL keeps code portable and cleaner.
✅ Practical takeaways
Prefer HQL for portability and to keep queries aligned with your Java model
(entities & properties).
Use [Link]() / [Link]() for simple primary-key lookups; use HQL for
searches/filters that need other columns or joins.
Only fall back to native SQL when HQL/JPA can’t express what you need.
📝 In short:
HQL lets you query objects (entities) instead of tables — write FROM Entity WHERE
property = :value and Hibernate will convert it to SQL and return typed Java objects.
package org.hibernate_hqlDemo;
import [Link];
import [Link];
@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
Hibernate Notes 85
[Link] = laptopId;
}
@Override
public String toString() {
return "Laptop{" +
"laptopId=" + laptopId +
", brand='" + brand + '\'' +
Hibernate Notes 86
", model='" + model + '\'' +
", price=" + price +
", color='" + color + '\'' +
'}';
}
}
package org.hibernate_hqlDemo;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
Hibernate Notes 87
// Now this time not fetching based on the primary key but based on the b
rand. For that we are using HQL
// If it is SQL - select * from Laptop where brand = "Apple"
// If it is HQL - From Laptop where brand = "Apple"
// [Link](l1);
// [Link]();
[Link]();
[Link]();
}
}
Hibernate Notes 88
⚡selecting
Hibernate — HQL: parameters &
specific columns
🎯 Goal
Show how to write HQL queries with parameters, fetch by different properties (not
just the PK), select single columns vs multiple columns, and handle the results in
Java.
🧩 Quick ideas
HQL works with entities and properties (not tables/columns).
You can filter by any property (brand, ram, etc.), not only the primary key.
For string filters use single quotes (or LIKE ) inside literals — or pass values
with parameters (preferred).
Hibernate Notes 89
[Link](1, "Asus");
[Link](2, 32);
If you use plain ? without numbers you get an error like "unlabeled ordinal
parameters" — always use ?1 , ?2 or named params.
Hibernate Notes 90
When you select multiple columns HQL returns each row as an Object[]
(columns in the order you selected them). You must cast elements to the
expected types when using them.
✅ Practical takeaways
Use named parameters ( :name ) for clarity; use ?1 , ?2 if you prefer positional
— never use unlabeled ? .
If you need single property values, select that property and use the
appropriate typed Query<T> (e.g., [Link] ).
HQL removes boilerplate of mapping ResultSet → objects; you get typed results
directly (or Object[] for multi-column selects).
📝 In short:
With HQL you can easily parameterize queries and choose whether to fetch whole
entities, single properties, or multiple properties. Use named params or numbered
positional params, and handle List<T> vs List<Object[]> appropriately when
processing results.
⚡LazyHibernate —
Fetching)
get() vs load() (Eager vs
🎯 Goal
Understand the difference between Hibernate’s get() and load() methods — how
they relate to eager and lazy fetching, and what to use in modern Hibernate
versions.
🧩 Overview
Both methods are used to fetch an entity by its primary key, but they behave
differently in when and how the data is fetched.
Hibernate Notes 91
When Query
Method Fetch Type Returns Notes
Executes
Even if you don’t use the returned object, the query still runs.
✅ Use when:
You need the full entity right away (e.g., display or modify its fields immediately).
Does not hit the database until you access a property or print the object.
Hibernate Notes 92
📊 Behavior example
Laptop laptop = [Link]([Link], 2);
// No SQL yet
[Link]([Link]()); // SQL executes here
📊 Behavior example
Laptop laptop = [Link]([Link]).getReference(2);
// No SQL here
[Link]([Link]()); // SQL runs here
🔬 Comparison Summary
Feature get() load() / getReference()
Use Case Need data right away Delay loading until needed
✅ Best Practices
Use [Link]() when you know you’ll need the entity right away.
Hibernate Notes 93
Avoid deprecated load() — use getReference() instead.
Remember: lazy fetching saves resources only if you don’t access the object
later.
📝 In short:
get() is eager, fetching data immediately.
Use get() for immediate access, and getReference() when you want on-demand
loading.
⚡Example)
Hibernate — Level 2 Cache (EhCache
🎯 Goal
Understand how to implement Hibernate Level 2 Cache using EhCache so that
multiple sessions can share cached entities, reducing database queries.
🧩 Overview
Hibernate provides two levels of caching:
Level 1
Session (per
transaction)
✅ Built-in, no config needed
Level 2
SessionFactory
(global)
❌ Requires external cache
(EhCache, Caffeine)
Key: Level 2 cache allows multiple sessions to reuse the same entity without
hitting the database again.
Hibernate Notes 94
<dependency>
<groupId>[Link]</groupId>
<artifactId>ehcache</artifactId>
<version>3.9.10</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>[Link]-api</artifactId>
<version>2.0.0</version>
</dependency>
<property name="[Link].use_second_level_cache">true</property>
<property name="[Link].factory_class">
[Link]
</property>
<property name="[Link]">
[Link]
</property>
@Entity
@Cacheable
public class Laptop {
@Id
Hibernate Notes 95
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
// Getters, setters, toString()...
}
Behavior:
With @Cacheable & Level 2 cache: SQL executes once, second fetch comes
from cache.
📊 Console Example
select * from Laptop where laptopId=2 // First session
Laptop{...}
🔬 Key Points
Feature Level 1 Cache Level 2 Cache
Hibernate Notes 96
Feature Level 1 Cache Level 2 Cache
Enabled by default? ✅ ❌
Annotation required ❌ ✅ @Cacheable
✅ Best Practices
Always use @Cacheable on entities you expect to reuse across sessions.
📝 In short:
Level 1 cache is session-scoped and automatic.
Level 2 cache is SessionFactory-scoped, requires @Cacheable and an external
provider (like EhCache).
This reduces redundant database queries when fetching the same entity across
multiple sessions.
Hibernate Notes 97
In Hibernate, the 'mappedBy' attribute is crucial when defining one-to-many relationships, as it determines which class or table holds the foreign key. By using 'mappedBy', you indicate that one side of the relationship is inverse and does not own the association; instead, the other side manages the foreign key. This prevents redundancy and unnecessary table creation since Hibernate will not create an additional join table. It ensures data integrity by correctly mapping the relationship with consistent and coherent data representation in the database, avoiding data duplication and inconsistency .
Using Hibernate's XML configuration offers several benefits over annotations: a centralized configuration file can be easier to maintain and reduces the spread of configuration details throughout the codebase. This can also improve separation of concerns, ensuring that entity classes remain clean and focused on business logic rather than persistence configuration. Additionally, XML configurations can provide more flexibility for switching databases or adjusting environment-specific settings without modifying source code .
Using the "update" option in the Hibernate hbm2ddl.auto property is intended primarily for development environments. It dynamically alters table schemas to reflect changes in entity definitions without removing old columns. However, in a production environment, this approach can introduce significant risks, such as unintended schema alterations if entity mappings are not meticulously controlled, potentially leading to data loss or application failures. It could also cause performance issues if large-scale schema updates are required dynamically, stressing the production database with unnecessary changes .
HQL, or Hibernate Query Language, resembles SQL but is designed for querying against Java objects and their properties, rather than tables and columns. This provides database independence, object-oriented programming benefits, and type safety through generics. HQL queries are automatically converted into SQL by Hibernate, offering portability across different database systems and cleaner code. However, one challenge is the learning curve for developers unfamiliar with HQL syntax. Additionally, while HQL can handle most operations, there are cases where native SQL queries are needed for performance optimization or database-specific functionality, which could complicate application logic .
Hibernate manages transactions using the beginTransaction() and commit() methods within a session. To ensure data consistency and integrity, changes made to the database are encapsulated within transactions. This prevents partially completed operations and ensures all operations are completed successfully or none at all in case of failures. Not handling transactions properly can lead to data inconsistencies and the possibility that changes are not committed to the database; for instance, if a transaction is not committed, Hibernate does not save the changes permanently .
Many-to-many relationships in Hibernate are more complex than one-to-many relationships because they require an additional join table to store the association between two entities, with each record representing a pair of associated IDs. This differs from one-to-many relationships, where a single foreign key column in the child table can suffice. The ownership of the relationship and management involves using @ManyToMany annotations on both sides of the relationship while configuring one side as the owner with the 'mappedBy' attribute on the inverse side to ensure a coherent mapping and avoid redundant join tables .
Lazy fetching in Hibernate postpones the retrieval of associated objects until they are explicitly accessed, which can enhance performance by reducing initial loading times and memory usage since only needed data is loaded. However, it can lead to additional fetch calls and higher latency when these objects are eventually accessed. If not managed properly, lazy loading can cause the "N+1 selects problem," leading to inefficient database access patterns which may negate its intended benefits .
Eager loading in Hibernate automatically retrieves related entities, which simplifies code when relationships are frequently navigated. However, this can lead to performance challenges, such as loading unnecessary data, increasing memory usage, and slowing down the application due to massive data retrieval. Managing these challenges involves selectively choosing eager fetching only when justified and necessary. Another solution is to use dynamic profiling or lazy fetching for particular use-cases, carefully considered through testing and profiling to ensure performance is not hindered while retaining data integrity .
Hibernate's caching strategies, including L1 and L2 caches, improve application performance by reducing the number of database hits. The L1 cache operates at the session level, ensuring within-session repeated database access is minimized. L2 cache extends this capability beyond a single session, thus sharing cached data across sessions. However, caching can lead to stale data if not managed correctly, as changes in the database might not immediately reflect in the application due to the cache. Moreover, improper use of caching can introduce unnecessary complexity and potential performance bottlenecks if cache size and eviction policies are not carefully controlled .
The SessionFactory in Hibernate is a heavyweight object that serves as a factory for session instances, representing a thread-safe cache of compiled mappings for a single database. It is crucial for efficient resource management, as it is intended to be created once and shared across the application. Sessions, however, are lightweight instances that provide the interface for data persistence operations. Since each Session is not thread-safe, it should not be reused across transactions. Properly opening and closing sessions minimizes memory leaks and resource contention. Managing these resources efficiently ensures optimal application performance .