0% found this document useful (0 votes)
17 views97 pages

Hibernate Notes

Hibernate is an Object Relational Mapping (ORM) framework that simplifies data persistence in Java applications by automating the mapping between Java objects and database tables, reducing the need for manual SQL queries. It enhances developer productivity and maintainability by allowing for cleaner code and automatic table creation. The document also outlines practical steps for implementing Hibernate, including project setup, configuration, and managing transactions.

Uploaded by

vijay kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views97 pages

Hibernate Notes

Hibernate is an Object Relational Mapping (ORM) framework that simplifies data persistence in Java applications by automating the mapping between Java objects and database tables, reducing the need for manual SQL queries. It enhances developer productivity and maintainability by allowing for cleaner code and automatic table creation. The document also outlines practical steps for implementing Hibernate, including project setup, configuration, and managing transactions.

Uploaded by

vijay kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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).

However, as applications grow, developer productivity and maintainability


become key — and that’s where Hibernate comes in.

🧠 Key idea
Java is object-oriented, everything revolves around objects.

Databases are relational, everything revolves around tables.

With plain JDBC, developers have to manually write SQL queries to bridge
these two worlds — converting objects into database rows and vice versa.

Hibernate automates this mapping process using ORM (Object Relational


Mapping), so you don’t have to write repetitive SQL by hand.

🚀 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.

Boosts productivity — less boilerplate, cleaner code.

Serves as a foundation for understanding Spring Data JPA, which builds on


similar ORM principles.

Hibernate Notes 1
📝 In short: JDBC works fine, but Hibernate makes data handling faster, simpler,
and more developer-friendly through ORM.

⚡ORMHibernate — What is Hibernate & Why


🎯 Goal
Understand what Hibernate is, what ORM means, and how it simplifies data
persistence in Java applications.

🧩 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).

Databases are relational — data is stored in tables and rows.

When using JDBC, developers must manually write SQL to insert, update, or
fetch data from tables.

This means:

Writing repetitive queries.

Managing SQL syntax and data types.

Handling caching and optimization manually.

💡 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 .

It creates a table based on this class:

Table name → student

Columns → correspond to class fields ( rollNo , name , age )

Column types → matched with Java data types ( int → INTEGER , String → TEXT ,
etc.)

Each object instance → becomes one row in the table.

🧠 So, ORM essentially says:


“Give me your object, and I’ll take care of saving it to the database.”

🚀 Benefits of Hibernate
No manual SQL: Hibernate handles CRUD operations automatically.

Productivity boost: Less boilerplate, faster development.

Maintainability: Cleaner, abstracted code.

Database independence: Switch from MySQL to PostgreSQL easily.

Performance: Built-in caching and query optimization.

📝 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!

Created a new Maven project named HibProject

Chose JDK 21 (any version above works great)

⚙️ 2️⃣ Adding Required Dependencies


In the [Link] , I added:

Hibernate Core dependency

PostgreSQL driver (since I’m using Postgres DB in pgAdmin)

📦 Both libraries were pulled from Maven Central Repository:


Searched → “hibernate-core”

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.

In the upcoming step, I’ll be creating:

Entity class (like Student )

Hibernate configuration file

Session factory setup

And saving objects directly into the database 🙌

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.

🧩 Creating the Student Class


Create a simple POJO (Plain Old Java Object) named Student .

Fields:

int rollNumber

String sName

int sAge

Generate:

Getters and setters for all fields.

toString() method for easy printing.

Purpose: Holds student data that can later be saved to the database.

🧠 Working with Student Objects


In main() :

1. Create a Student object:

Student s1 = new Student();

2. Set data:

[Link](101);
[Link]("Naveen");
[Link](30);

3. Printing the object shows populated data.

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).

Hibernate simplifies this with methods like save() .

Challenge: save() needs a Session — cannot be instantiated directly because


it’s an interface.

🚀 Session & SessionFactory Workflow


Session: Represents one unit of work with the database.

SessionFactory: Heavyweight object to create sessions.

Use one per database to optimize resources.

Multiple sessions can be created for different units of work.

Steps to persist an object:

1. Create a Configuration object (handles setup and mappings).

2. Build a SessionFactory from the configuration.

3. Open a Session from the SessionFactory.

4. Call [Link](studentObject) to save the object.

🔮 Common Pitfalls
Directly calling [Link]() without initializing the session →
NullPointerException.

Hibernate cannot connect to the database without proper configuration:

Database type (e.g., Postgres)

Username & password

Database name

Configuration is essential before any object can be saved.

📝 Summary
Created a Student POJO with fields, getters, setters, and toString() .

Learned the Session & SessionFactory pattern in Hibernate.

Hibernate Notes 6
Direct object persistence requires proper configuration.

Next step: configure Hibernate with database details and successfully save
objects.

⚡DataHibernate — Configuration & Saving


🎯 Goal
Learn how to configure Hibernate using XML, map entities, manage transactions,
and automatically create tables to save data in the database.

🧩 Where to Configure Hibernate?


Hibernate supports XML configuration or annotations.

For XML:

Place configuration files in the resources folder.

Use the [Link]() method to load the XML file.

💡 Default XML filename: [Link] .

You can use a different name, but then you must specify it in the configuration.

🧠 Setting Up XML Configuration


1. Create a file in resources named [Link] .

2. Use the hibernate-configuration tag and a nested session-factory tag.

3. Define database connection properties:

<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

2. Annotations (JPA standard)

Example using annotations:

Add @Entity on the class.

Add @Id on the primary key field.

Add the class in code before configuration:

[Link]([Link]);

Hibernate now knows which class to persist.

🚀 Transactions and Saving Data


Saving data in Hibernate requires transactions.

Steps:

Begin transaction:

Transaction tx = [Link]();

Save object:

[Link](student);

Commit transaction:

Hibernate Notes 8
[Link]();

💡 Without committing, data is not persisted to the database.


🔄 Automatic Table Creation
Hibernate can create tables automatically using the property:

<property name="[Link]">update</property>

Options:

Value Behavior

none Do nothing

create Create table every time (drops if exists)

create-drop Create and drop after session ends

update Create table if missing, update schema without removing old columns

update is recommended for development.

Avoid update in production.

✅ Result
After configuration, mapping, and transaction management:

Hibernate creates the table (if not present).

Saves objects without writing SQL.

Data can be seen directly in the database.

📝 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];

public class Main {


public static void main(String[] args) {

Student student = new Student();


[Link]( 1 );
[Link]( "John Doe" );
[Link]( 30 );

// 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]();

// Now, if you go back to database principles, we got this asset property.

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>

<!-- Exception in thread "main" [Link]


ption: could not execute statement [ERROR: relation "student" does not exist--
>
<!-- Position: 13] [insert into Student (age,name,rollNo) values (?,?,?)]-->
<!-- if I want hibernate to create a table for me to do that-->
<!-- So even if you don't have a table, it will create a table. But the proble
m is it will create. It will try to create a new table every time.-->
<!-- Update says I will use a table if the table exists. It also says if there's
a change in schema I will do that. -->
<!-- Maybe I will add a new column, but it will not remove the old columns
if we do that, if the table does not exist, it will create the table exists. It will use
it.-->
<property name="[Link]">update</property>

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;

public int getRollNo() {


return rollNo;
}

public void setRollNo(int rollNo) {


[Link] = rollNo;
}

public int getAge() {


return age;
}

public void setAge(int age) {


[Link] = age;
}

public String getName() {


return name;
}

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.

🧩 Storing Data in Database


Data can be stored in a database using Hibernate by creating object instances
and saving them.

Example: Student object with fields rollNo , name , age .

Hibernate automatically generates and executes SQL queries to insert data.

💡 Key consideration: Primary key uniqueness


rollNo is the primary key.

Trying to save the same rollNo again causes:

duplicate key value violates unique constraint

Solution: Use a unique rollNo for each record.

Hibernate Notes 13
Example flow:

1. Add a new student: Kiran , rollNo=102 , age=25 → success.

2. Add another student: Harsh , rollNo=103 , age=21 → success.

3. Add another student: Sushil , rollNo=104 , age=20 → success.

🧠 Viewing SQL Queries


Hibernate uses JDBC behind the scenes — SQL queries are generated
automatically.

To view queries, add the property in [Link] :

<property name="hibernate.show_sql">true</property>

To format SQL in a readable structure:

<property name="hibernate.format_sql">true</property>

Example output:

insert into Student (age,name,rollNo) values (?,?,?)

Proper formatting helps when queries are complex.

🧩 Specifying Database Dialect


SQL syntax can vary across databases (PostgreSQL, MySQL, etc.).

Hibernate allows specifying dialect:

<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 .

2. Set Hibernate properties:

Hibernate Notes 14
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="[Link]">[Link]
</property>

1. Run the application.

2. Verify data in the database.

3. Observe queries printed in the console in a readable format.

📝 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.

🧩 Optimizing Hibernate Code


1️⃣ Avoid Deprecated Methods
[Link]() is deprecated in Hibernate 6.0+.

Reason: Hibernate aligns with JPA standards.

Recommended replacement:

Hibernate Notes 15
[Link](student);

ensures the entity is managed and saved according to JPA


persist()

conventions.

2️⃣ Managing Resources Properly


SessionFactory is heavyweight and consumes system resources.

Always close Session and SessionFactory after use to avoid memory leaks.

Options:

1. Try-with-resources:

try (SessionFactory sf = new Configuration().configure().buildSessionFact


ory();
Session session = [Link]()) {
[Link](student);
}

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 .

Refactored version merges configuration in one statement:

SessionFactory sf = new Configuration()


.addAnnotatedClass([Link])
.configure()
.buildSessionFactory();

Benefits:

Fewer statements

Hibernate Notes 16
Easier to maintain

Clean, readable code

4️⃣ Persisting a New Record Example


Student student = new Student("Avni", 106, 21);

[Link](student);

[Link]();
[Link]();

✅ SQL query generated successfully


✅ No warnings or deprecated method usage
🧩 Fetching Data
Once multiple records exist, you may want to read/fetch data instead of
inserting.

Hibernate provides methods to retrieve objects from the database.

Next steps:

Explore [Link]() and [Link]() for fetching.

Learn how to handle lists of records.

Combine fetching with proper resource management.

📝 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).

2️⃣ Fetching by Primary Key


Hibernate provides multiple methods:

Student student1 = null;

// Using find() — modern replacement for get()


student1 = [Link]([Link], 3); // fetch student with PK = 3
// Fetch using primary key with Hibernate:

// Equivalent options (Hibernate 6+):


// Returns proxy if not already loaded (lazy fetch)
student1 = [Link]([Link]).getReference(3);

// Also returns proxy, similar to getReference


student1 = [Link]([Link]).load(3);

Notes:

find() immediately fetches the entity from the database.

get() (deprecated) behaved similarly.

byId().getReference() or byId().load() return proxies (lazy fetching).

Hibernate Notes 18
3️⃣ Handling Missing Data
If the record does not exist (e.g., PK = 9):

student1 = [Link]([Link], 9);


if (student1 != null) {
[Link]([Link]());
} else {
[Link]("Student not found");
}

Trying to access fields on a null object will throw a NullPointerException.

Always check for null before performing operations.

4️⃣ What Hibernate Does Behind the Scenes


Hibernate automatically:

Generates SQL queries.

Maps results to your entity objects.

Handles conversions between SQL and Java types.

Example query generated by find() :

SELECT * FROM Student WHERE id = 3;

5️⃣ Deprecated Methods


[Link]() and [Link]() is deprecated in Hibernate 6.

If used, it may return a proxy and can throw exceptions if the session is
closed.

Recommended: use find() for fetching by primary key.

📝 Summary:
For fetching data:

Use [Link]([Link], primaryKey) in Hibernate 6.

No transaction is needed for simple reads.

Always check for nulls to avoid exceptions.

Hibernate Notes 19
Avoid deprecated methods like get() or load() .

Hibernate automatically converts SQL results to Java objects.

⚡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

Create persist() replaces save() ✅ Yes


Read find() replaces get() ❌ No
Update merge()
replaces update() or
saveOrUpdate()
✅ Yes
Delete remove() replaces delete() ✅ Yes
🧠 Updating Data with merge()
update() and saveOrUpdate() are deprecated in Hibernate 6+.

Use merge() , which:

Checks if the record exists with a SELECT query.

If it exists → updates it.

If it doesn’t → inserts it (similar to deprecated saveOrUpdate() ).

✅ Example

Hibernate Notes 20
Transaction tx = [Link]();

Student student = new Student();


[Link](103);
[Link]("Harsh");
[Link](23); // updated value

[Link](student);

[Link]();

🔍 What Happens Internally


Hibernate: select s1_0.rollNo, s1_0.age, s1_0.name from Student s1_0 where s1_
[Link]=?
Hibernate: update Student set age=?, name=? where rollNo=?

If the record doesn’t exist:

Hibernate: select ... where rollNo=?


Hibernate: insert into Student (age, name, rollNo) values (?, ?, ?)

💡 merge() works as an intelligent method — updates existing or inserts new.

🧩 Deleting Data with remove()


delete() is deprecated.

Use remove() instead.

To delete, Hibernate needs the entity object, not just the ID.

✅ Example
Transaction tx = [Link]();

Student student = [Link]([Link], 109); // fetch the object to delet


e
[Link](student);

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() .

Always commit after modification to persist changes.

Handle nulls safely — find() may return null if record doesn’t exist.

Verify in the database after commit.

🧩 Complete Update + Delete Snippet


SessionFactory sf = new Configuration().addAnnotatedClass([Link]).c
onfigure().buildSessionFactory();
Session session = [Link]();

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()

for modifications and commit changes for persistence.

⚡ Hibernate — Entity & Table Annotations


🎯 Goal
Learn how to customize how classes and fields map to database tables and
columns using Hibernate/JPA annotations ( @Entity , @Table , @Column , @Id , @Transient )
and understand the effect of [Link] ( create vs update ).

🧩 Where annotations fit


By default:

Class name → becomes the entity name → becomes the table name.

Field names → become column names.

Annotations let you override those defaults without renaming your Java
classes/fields.

🧠 Key annotations & how they change mapping


@Entity

Marks a class as a persistent entity managed by Hibernate/JPA.

Optionally accepts a name ( @Entity(name = "alien_entity") ) which changes the


entity name used in queries.

@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).

🧩 Example behaviors shown in the demo


Creating an Alien class with fields alienId , alienName , techStack .

@Entity + @Id on alienId → marks the class as an entity with primary key.

@Table(name = "Alien_Table") → database table becomes Alien_Table .

@Column(name = "alienName_column") → column name becomes alienName_column .

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

removes existing data).

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.

🔍 Quick examples (annotation snapshots)


Change entity name:

@Entity(name = "alien_entity")

Change table name:

@Table(name = "Alien_Table")

Change column name:

@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.

Pick [Link] mode carefully:

create for experiments (table recreated each run).

during iterative development when you want Hibernate to create


update

missing tables and apply non-destructive changes.

📝 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.

🧩 Problem — why embeddables?


Simple Java types (int, String ) map easily to JDBC types (INTEGER, VARCHAR).

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.

✅ Solution: @Embeddable + embedded field


1. Create a plain Laptop class with fields (brand, model, price, color),
getters/setters, and toString .

2. Annotate Laptop with @Embeddable .

3. In the Alien entity, replace the simple field (or @Transient ) with a reference:

private Laptop laptop;

4. Persist an Alien whose laptop is a Laptop instance. Hibernate will map the Laptop

fields into columns of the Alien table.

✨ What happens at runtime (demo behavior)


Before @Embeddable — attempting to persist an Alien with a Laptop field raised
the JDBC-type error.

After @Embeddable — Hibernate creates columns for the Laptop fields on the Alien

table (brand, model, price, color) and inserts values:

Example DDL (from the demo):

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)
)

Persisting Alien inserts all fields (including embedded laptop columns).

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.

🧩 Example (essential lines from demo)


Laptop class:

@Embeddable
public class Laptop {
private String brand;
private String model;
private double price;
private String color;
// getters/setters, toString
}

Alien entity snippet:

@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;
private Laptop laptop; // embedded complex type
// getters/setters, toString
}

Persist & read:

Laptop l1 = new Laptop(...);


Alien a1 = new Alien(...);
[Link](l1);

[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.).

@Embeddable avoids creating a separate table while giving structured access to


sub-fields.

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];

public class Main {


public static void main(String[] args) {

Laptop l1 = new Laptop();


[Link]("Apple");
[Link]("Macbook Pro");
[Link](2200.00);
[Link]("Grey");

Alien a1 = new Alien();


[Link](1);
[Link]("Sai Mahendra Penumakula");
[Link]("Java");

Hibernate Notes 28
[Link](l1);

Configuration cfg = new Configuration().configure();


// IMPORTANT: register your annotated entity
[Link]( [Link] );
SessionFactory sf = new Configuration().addAnnotatedClass([Link]).
configure().buildSessionFactory();

Session session = [Link]();


Transaction tx = [Link]();
[Link](a1);
[Link]();

Alien a2 = [Link]([Link], 1);


[Link](a2);

[Link]();
[Link]();
[Link](a1);

}
}

package [Link];

import [Link].*;

// Changing the entity name - @Entity(name = "alien_entity")


// insert
// into
// alien_entity

// Changes Table Name - @Table(name = "Alien_Table")


//Hibernate:
//create table Alien_Table (
// alienId integer not null,
// alienName varchar(255),
// techStack varchar(255),

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;

// we don't want techStack to be stored in db. At the time we have to use on


e of the annotation called @Transient.
// sometime, when we build application, we want certain fields to be there f
or the processing, right?
// Maybe we want to perform some operation, maybe we want to store som
e data only in the object but not in database.
// Hibernate:
// create table Alien_Table (
// alienId integer not null,
// alienName_column varchar(255),
// primary key (alienId)
// )
//Hibernate:
// insert

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;

public int getAlienId() {


return alienId;
}

public void setAlienId(int alienId) {


[Link] = alienId;
}

public String getAlienName() {


return alienName;
}

public void setAlienName(String alienName) {


[Link] = alienName;
}

public String getTechStack() {


return techStack;

Hibernate Notes 31
}

public void setTechStack(String techStack) {


[Link] = techStack;
}

public Laptop getLaptop() {


return laptop;
}

public void setLaptop(Laptop laptop) {


[Link] = laptop;
}

@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 {

private String brand;


private String model;
private double price;
private String color;

public String getBrand() {


return brand;
}

public void setBrand(String brand) {


[Link] = brand;
}

public String getModel() {


return model;
}

Hibernate Notes 33
public void setModel(String model) {
[Link] = model;
}

public String getColor() {


return color;
}

public void setColor(String color) {


[Link] = color;
}

public double getPrice() {


return price;
}

public void setPrice(double price) {


[Link] = price;
}

@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.

But real-world requirements often need laptops to have identity or multiplicity:

Laptop may need its own primary key (it is a first-class entity).

One alien may have multiple laptops (0..n).

A laptop might be reassigned from one alien to another.

When multiplicity or identity matters, Laptop should be a separate table/entity


(not @Embeddable ).

✅ Basic mapping approaches (high level)


1) One-to-One
Use when a single alien maps to a single laptop.

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

Alien(alienId, alienName, tech)


Laptop(laptopId, brand, model, alienId) <-- alienId as FK for 1:1

2) One-to-Many / Many-to-One
One Alien → Many Laptop (from alien perspective: OneToMany).

Each Laptop belongs to one Alien (from laptop perspective: ManyToOne).

Typical modeling: put the foreign key in the child table (Laptop), since laptops
belong to one alien.

Why put FK in laptop?

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

Alien(alienId, alienName, tech)


Laptop(laptopId, brand, model, alienId) <-- many laptops reference one alien

3) When NOT to put FK and the join-table option


If you don’t want to add FK to either table (keep tables “clean”), create a third
table to map relations (link table).

That third table records which alien has which laptop (useful for flexible
mappings or when neither side should own the FK).

Schema idea (join table)

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

🧠 Practical decision guide (from the demo)


Hibernate Notes 36
Use @Embeddable when the value has no identity and should be flattened into
the same table (simple, fixed structure).

Make a separate entity when the sub-object needs identity, lifecycle, or


multiplicity (e.g., multiple laptops per alien).

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.

Recognize the relationship type from both perspectives:

Alien → Laptop = OneToMany

Laptop → Alien = ManyToOne

📝 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.

⚡ Hibernate — One-to-One mapping


🎯 Goal
Show how to map a one-to-one relationship in Hibernate — e.g., an Alien has one
Laptop (and each Laptop belongs to one Alien ) — and how to persist/read the linked

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.

🔧 Key code / annotations (conceptual)


Laptop (entity with id):

@Entity
public class Laptop {
@Id
private int laptopId;
private String brand;
private String model;
private double price;
private String color;
// getters/setters, toString
}

Alien (owns the one-to-one relationship):

@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 :

SessionFactory sf = new Configuration()


.addAnnotatedClass([Link])
.addAnnotatedClass([Link])
.configure()

Hibernate Notes 38
.buildSessionFactory();

Session session = [Link]();


Transaction tx = [Link]();

[Link](l1); // laptop first


[Link](a1); // alien that references laptop

[Link]();
[Link]();
[Link]();

🧠 What Hibernate did (demo behavior)


Hibernate created both tables ( Alien , Laptop ) and added a foreign key column
in the Alien table referencing Laptop (so Alien stores the laptop id).

DDL sequence (demo outcome):

Create Laptop table.

Create Alien table (with a unique FK column for laptop to enforce 1:1).

Insert laptop row(s).

Insert alien row(s) with laptopId foreign key value.

Verifying: pgAdmin shows laptop row and alien row; the alien row contains the
laptopId reference.

⚠️ Notes & small gotchas from the demo


You must register both annotated classes with the Configuration (or they won’t
be recognized).

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 .

Use cascade if you want saves/deletes on the parent to propagate


automatically.

Next step: map one-to-many / many-to-one (one alien owning multiple


laptops) — mapping becomes different (FK on child table), covered in the next
video.

📝 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;

public int getAlienId() {


return alienId;

Hibernate Notes 40
}

public void setAlienId(int alienId) {


[Link] = alienId;
}

public String getAlienName() {


return alienName;
}

public void setAlienName(String alienName) {


[Link] = alienName;
}

public String getTechStack() {


return techStack;
}

public void setTechStack(String techStack) {


[Link] = techStack;
}

public Laptop getLaptop() {


return laptop;
}

public void setLaptop(Laptop laptop) {


[Link] = laptop;
}

@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;

public int getLaptopId() {


return laptopId;
}

public void setLaptopId(int laptopId) {


[Link] = laptopId;
}

public String getBrand() {


return brand;
}

public void setBrand(String brand) {


[Link] = brand;
}

public String getModel() {


return model;
}

Hibernate Notes 42
public void setModel(String model) {
[Link] = model;
}

public String getColor() {


return color;
}

public void setColor(String color) {


[Link] = color;
}

public double getPrice() {


return price;
}

public void setPrice(double price) {


[Link] = price;
}

@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];

public class Main {


public static void main(String[] args) {

Laptop l1 = new Laptop();


[Link](1);
[Link]("Apple");
[Link]("Macbook Pro");
[Link](2200.00);
[Link]("Grey");

Alien a1 = new Alien();


[Link](1);
[Link]("Sai Mahendra Penumakula");
[Link]("Java");
[Link](l1);

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();

Session session = [Link]();


Transaction tx = [Link]();
[Link](l1);
[Link](a1);
[Link]();

Alien a2 = [Link]([Link], 1);


[Link](a2);

[Link]();
[Link]();
[Link](a1);

}
}

⚡ Hibernate — OneToMany / ManyToOne


🎯 Goal
Show how to model a one-to-many relationship in Hibernate — e.g., one Alien can
own many Laptop instances — and how to persist/read the linked entities so the DB
schema and data reflect that relationship.

🧩 Problem — mapping multiple child objects


An Alien may have multiple Laptop objects (a list), not a single Laptop .

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 ).

✅ Two ways demo showed


1) Default @OneToMany (owner = parent) → join table
If Alien declares @OneToMany and you don't tell Hibernate who owns the
relationship, Hibernate creates a third (join) table: alien_laptop .

That join table contains two columns (alienId, laptopId); their combination acts
as a composite key.

This is useful for many-to-many or when you intentionally want a separate


association table.

2) Bidirectional mapping (preferred here) → FK on child


Make relationship bidirectional:

Alien has @OneToMany(mappedBy = "alien") private List<Laptop> laptops;

Laptop has @ManyToOne private Alien alien;

mappedBy = "alien" tells Hibernate: [Link] is the owner — put the FK on


Laptop table.

Result: no join table; Laptop gets an alien_id FK column, and each laptop row
references the owning alien.

✨ Demo behaviour (what happened)


Created several Laptop objects ( l1 , l2 , l3 ) and an Alien a1 with
[Link]([Link](l1,l2,l3)) .

Also set the child side [Link](a1) , [Link](a1) , [Link](a1) .

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.

🧩 Key code (essential snippets from demo)


Alien (owner side not owning — mappedBy used):

@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;

@OneToMany(mappedBy = "alien")
private List<Laptop> laptops;
// getters/setters, toString
}

Laptop (owning side — FK lives here):

@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
}

Persisting (demo flow):

Hibernate Notes 47
[Link](a1); [Link](a1); [Link](a1);
[Link]([Link](l1,l2,l3));

[Link](l1);
[Link](l2);
[Link](l3);
[Link](a1);
[Link]();

✅ Practical takeaways & tips (from demo)


If you want the child table to hold the FK, make the association bidirectional
and put mappedBy on the parent side.

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.

Feature [Link]() [Link]() (Java 9+)

Mutable elements, immutable Immutable (cannot modify elements or


Mutability
size size)

Does not allow null elements


Nulls Allows null elements
(throws NPE )

Creates a new, optimized internal


Backing Backed by the original array
representation

Fixed-size list with modifiable


Use Case Immutable, thread-safe collections
elements

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;

// From the Laptop Perspective - Multiple Laptops belong to one Alien


@ManyToOne
private Alien alien;

public int getLaptopId() {


return laptopId;
}

public void setLaptopId(int laptopId) {


[Link] = laptopId;
}

public String getBrand() {


return brand;
}

public void setBrand(String brand) {


[Link] = brand;
}

public String getModel() {

Hibernate Notes 49
return model;
}

public void setModel(String model) {


[Link] = model;
}

public String getColor() {


return color;
}

public void setColor(String color) {


[Link] = color;
}

public double getPrice() {


return price;
}

public void setPrice(double price) {


[Link] = price;
}

public Alien getAlien() {


return alien;
}

public void setAlien(Alien alien) {


[Link] = alien;
}

@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;

public int getAlienId() {


return alienId;
}

public void setAlienId(int alienId) {


[Link] = alienId;

Hibernate Notes 51
}

public String getAlienName() {


return alienName;
}

public void setAlienName(String alienName) {


[Link] = alienName;
}

public String getTechStack() {


return techStack;
}

public void setTechStack(String techStack) {


[Link] = techStack;
}

public List<Laptop> getLaptops() {


return laptops;
}

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_onetomany_manytoone;

Hibernate Notes 52
import [Link];
import [Link];
import [Link];
import [Link];

import [Link];

public class Main {


public static void main(String[] args) {

Laptop l1 = new Laptop();


[Link](1);
[Link]("Apple");
[Link]("Macbook Pro");
[Link](2200.00);
[Link]("Grey");

Laptop l2 = new Laptop();


[Link](2);
[Link]("Dell");
[Link]("Dell XPS");
[Link](1800.00);
[Link]("Black");

Laptop l3 = new Laptop();


[Link](3);
[Link]("HP");
[Link]("HP Notebook");
[Link](1900.00);
[Link]("Silver");

Alien a1 = new Alien();


[Link](1);
[Link]("Sai Mahendra Penumakula");
[Link]("Java");
[Link]([Link](l1, l2, l3));

// here we are mentioning both laptop belongs to Alien a1


// To set this we have created the Alien alien reference in Laptop class wh

Hibernate Notes 53
ich Many to One - Many Laptops belong to one alien
[Link](a1);
[Link](a1);
[Link](a1);

// Configuration cfg = new Configuration().configure();


// // IMPORTANT: register your annotated entity
// [Link]( [Link] );
// [Link]( [Link] );
SessionFactory sf = new Configuration().addAnnotatedClass([Link]).
addAnnotatedClass([Link]).configure().buildSessionFactory();

Session session = [Link]();


Transaction tx = [Link]();
[Link](l1);
[Link](l2);
[Link](l3);
[Link](a1);
[Link]();

Alien a2 = [Link]([Link], 1);


[Link](a2);
// [Link](a1);
[Link]();
[Link]();

}
}

⚡ 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.

🧩 Problem — when many talk to many


In many-to-many, neither side holds a single FK column — the relationship
needs a mapping table (join table) that stores pairs of IDs (e.g., alien_id ,
laptop_id ).

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.

✅ How the demo implements ManyToMany


1. Convert both entities to hold lists:

Alien → List<Laptop> laptops

Laptop → List<Alien> aliens

2. Annotate the parent side with @ManyToMany (e.g., Alien ):

@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;

mappedBy = "laptops" points to the field name on the owning side.

4. Populate both sides in code (keep in-memory model consistent):

For each Alien , set [Link](...) .

For each Laptop , set [Link](...) .

5. Persist entities (demo persisted laptops then aliens).

✨ Demo behaviour (what happened)


Created 3 laptops and 3 aliens and assigned different overlaps:

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

laptop_alien ) — both sides tried to map the association.

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).

🧩 Key code (essential snippets from demo)


Alien (owning side):

@Entity
public class Alien {
@Id
private int alienId;
private String alienName;
private String techStack;

@ManyToMany
private List<Laptop> laptops;
// getters/setters
}

Laptop (inverse side):

@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
}

Setting up relationships in main :

[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]();

✅ Practical takeaways & tips


Many-to-many requires a join table. Hibernate will create it automatically
unless you customize it.

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] ).

After mapping correctly, you’ll see:

Alien table — alien data

Laptop table — laptop data

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;

public int getAlienId() {


return alienId;
}

public void setAlienId(int alienId) {


[Link] = alienId;
}

public String getAlienName() {

Hibernate Notes 58
return alienName;
}

public void setAlienName(String alienName) {


[Link] = alienName;
}

public String getTechStack() {


return techStack;
}

public void setTechStack(String techStack) {


[Link] = techStack;
}

public List<Laptop> getLaptops() {


return laptops;
}

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_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;

public int getLaptopId() {


return laptopId;
}

public void setLaptopId(int laptopId) {


[Link] = laptopId;
}

public String getBrand() {


return brand;
}

public void setBrand(String brand) {


[Link] = brand;
}

public String getModel() {


return model;
}

public void setModel(String model) {


[Link] = model;
}

Hibernate Notes 60
public String getColor() {
return color;
}

public void setColor(String color) {


[Link] = color;
}

public double getPrice() {


return price;
}

public void setPrice(double price) {


[Link] = price;
}

public List<Alien> getAliens() {


return aliens;
}

public void setAliens(List<Alien> aliens) {


[Link] = aliens;
}

@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];

public class Main {


public static void main(String[] args) {

Laptop l1 = new Laptop();


[Link](1);
[Link]("Apple");
[Link]("Macbook Pro");
[Link](2200.00);
[Link]("Grey");

Laptop l2 = new Laptop();


[Link](2);
[Link]("Dell");
[Link]("Dell XPS");
[Link](1800.00);
[Link]("Black");

Laptop l3 = new Laptop();


[Link](3);
[Link]("HP");
[Link]("HP Notebook");
[Link](1900.00);
[Link]("Silver");

Alien a1 = new Alien();


[Link](1);
[Link]("Sai Mahendra Penumakula");

Hibernate Notes 62
[Link]("Java");

Alien a2 = new Alien();


[Link](2);
[Link]("Prudhvi");
[Link]("Pega Developer");

Alien a3 = new Alien();


[Link](3);
[Link]("Gopichand");
[Link]("SAP Developer");

[Link]([Link](l1, l2));
[Link]([Link](l2, l3));
// [Link]([Link](l1));
// As we are holding one value prefer to use [Link]
[Link]([Link](l1));

// here we are mentioning both laptop belongs to Alien a1


// To set this we have created the Alien alien reference in Laptop class wh
ich Many to One - Many Laptops belong to one alien
[Link]([Link](a1, a3));
[Link]([Link](a1, a2));
[Link]([Link](a1));

// Configuration cfg = new Configuration().configure();


// // IMPORTANT: register your annotated entity
// [Link]( [Link] );
// [Link]( [Link] );
SessionFactory sf = new Configuration().addAnnotatedClass([Link]).
addAnnotatedClass([Link]).configure().buildSessionFactory();

Session session = [Link]();


Transaction tx = [Link]();
[Link](l1);
[Link](l2);
[Link](l3);
[Link](a1);

Hibernate Notes 63
[Link](a2);
[Link](a3);
[Link]();

Alien a5 = [Link]([Link], 1);


[Link](a5);
// [Link](a1);
[Link]();
[Link]();

}
}

⚡ Hibernate — Eager vs Lazy fetching


🎯 Goal
Explain Hibernate’s lazy and eager fetching behaviour for collections and single
associations, show how session-level caching affects observed SQL, and how to
change fetch strategy in code.

🧩 What happened in the demo (quick story)


The demo switched the mapping to One→Many (one Alien → many Laptop ).

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).

Making the collection eager ( fetch = [Link] ) caused Hibernate to load


laptops immediately (one join query).

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).

When lazy loads happen — accessing the collection (e.g.,


[Link]([Link]()) ) triggers the additional query to load the collection

if it hasn’t been loaded yet.

✅ How to reproduce / essential patterns (from demo)


Persisting data (same session):

SessionFactory sf = new Configuration().addAnnotatedClass([Link])


.addAnnotatedClass([Link])
.configure()
.buildSessionFactory();
Session session = [Link]();
Transaction tx = [Link]();
[Link](l1); [Link](l2); [Link](a1);
[Link]();

Same-session fetch (L1 cache — no SELECT shown if object was already in


session):

Alien a = [Link]([Link], 1); // may hit session cache

Force database fetch (new session) — opens a new session so L1 cache


won’t satisfy the find :

Hibernate Notes 65
Session session1 = [Link]();
Alien a3 = [Link]([Link], 1); // issues SELECT

Make collection eager — load laptop collection with the owner:

@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.

✨ Demo observations (SQL behaviour)


Lazy + same session: no additional SELECT for collection until you access it.

Lazy + different session / when accessed: Hibernate issues a query like:

select [Link], [Link], [Link] from Alien where alienId = ?

and when the collection is accessed:

select <join results> from Alien_Laptop join Laptop where Alien_alienId = ?

Eager: one join query fetching owner + collection columns immediately:

select [Link], [Link], [Link], l.*


from Alien a
left join Alien_Laptop al on [Link] = al.Alien_alienId
left join Laptop l on [Link] = al.laptops_laptopId
where [Link] = ?

⚖️ 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.

✅ Practical takeaways & tips


By default keep collections lazy and fetch only when required.

If you need cross-session caching (so multiple sessions share cached


entities), use a second-level cache (e.g., Ehcache/Caffeine) — demo
mentions those libraries.

To see what Hibernate SQL is doing, inspect the console output (set
hibernate.show_sql / format_sql as in earlier demos).

When debugging “why no SELECT?”, remember L1 cache: persistence + read


in the same session may avoid a DB round trip.

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;

// If we want to fetch eager we need to mention the property here


// @OneToMany(fetch = [Link])
// private List<Laptop> laptops;

public int getAlienId() {


return alienId;
}

public void setAlienId(int alienId) {


[Link] = alienId;
}

public String getAlienName() {


return alienName;
}

public void setAlienName(String alienName) {


[Link] = alienName;
}

public String getTechStack() {


return techStack;
}

public void setTechStack(String techStack) {


[Link] = techStack;
}

public List<Laptop> getLaptops() {


return 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;

public int getLaptopId() {


return laptopId;
}

public void setLaptopId(int laptopId) {


[Link] = laptopId;

Hibernate Notes 69
}

public String getBrand() {


return brand;
}

public void setBrand(String brand) {


[Link] = brand;
}

public String getModel() {


return model;
}

public void setModel(String model) {


[Link] = model;
}

public String getColor() {


return color;
}

public void setColor(String color) {


[Link] = color;
}

public double getPrice() {


return price;
}

public void setPrice(double price) {


[Link] = price;
}

@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];

public class Main {


public static void main(String[] args) {

Laptop l1 = new Laptop();


[Link](1);
[Link]("Apple");
[Link]("Macbook Pro");
[Link](2200.00);
[Link]("Grey");

Laptop l2 = new Laptop();


[Link](2);
[Link]("Dell");
[Link]("Dell XPS");
[Link](1800.00);
[Link]("Black");

Laptop l3 = new Laptop();


[Link](3);

Hibernate Notes 71
[Link]("HP");
[Link]("HP Notebook");
[Link](1900.00);
[Link]("Silver");

Alien a1 = new Alien();


[Link](1);
[Link]("Sai Mahendra Penumakula");
[Link]("Java");

Alien a2 = new Alien();


[Link](2);
[Link]("Prudhvi");
[Link]("Pega Developer");

[Link]([Link](l1, l2));
[Link]([Link](l3));

SessionFactory sf = new Configuration().addAnnotatedClass([Link]).


addAnnotatedClass([Link]).configure().buildSessionFactory();

Session session = [Link]();


Transaction tx = [Link]();
[Link](l1);
[Link](l2);
[Link](l3);
[Link](a1);
[Link](a2);
[Link]();

// Alien a5 = [Link]([Link], 1);


// Here we are trying to fetch the first alien which is holding two laptops
// [Link](a1);

/*

Hibernate: set client_min_messages = WARNING


Hibernate: alter table if exists Alien_Laptop drop constraint if exists FKd19

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.

// Creating a new session - openSession() will create a new session


Session session1 = [Link]();
// As we are fetching from the different session which will fire the select q
uery because the level one cache works in the same session.
Alien a3 = [Link]([Link], 1);
// [Link](a3);

/*
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]();

}
}

⚡ Hibernate — Level 1 & Level 2 Caching


🎯 Goal
Explain how Hibernate caching works — specifically, Level 1 (L1) and Level 2 (L2)
cache — with examples of session behavior, caching flow, and practical
implications.

🧩 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.

This happens due to caching — an in-memory data optimization technique built


into Hibernate.
Now, let’s explore how Hibernate manages this under the hood.

Hibernate Notes 76
⚙️ Caching Flow (Conceptually)
Imagine a 3-tier setup:

React Client → Server → Database

When a client requests data (e.g., Alien with ID 101):

1. The server opens a Hibernate Session (S1).

2. Hibernate sends a SQL query to fetch Alien 101 from the database.

3. The entity is stored in Session S1’s memory (cache).

4. Hibernate returns the data to the client.

Now, if the same session (S1) requests Alien 101 again:

Hibernate finds it in the session cache (L1).

No new SQL query is fired.

Data is returned directly from memory.

🧠 Level 1 Cache (L1 Cache)


Aspect Description

Scope Per session

Enabled by
default
✅ Always on
Stored in Hibernate’s internal session memory

Visibility Not shared across sessions

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:

Session session = [Link]();

// 1st fetch — goes to DB


Alien alien1 = [Link]([Link], 101);

Hibernate Notes 77
// 2nd fetch — comes from L1 cache, no DB hit
Alien alien2 = [Link]([Link], 101);

⚙️ Level 2 Cache (L2 Cache)


Aspect Description

Scope Across sessions

Enabled by
default
❌ Requires configuration
Purpose Share cached data between multiple sessions

Where stored External cache provider (Ehcache, Caffeine, Infinispan, etc.)

Standard Used JCache (JSR-107) API

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:

// Session 1 loads Alien 101


Session s1 = [Link]();
Alien a1 = [Link]([Link], 101);
[Link](); // Entity goes to L2 cache if configured

// Session 2 requests the same


Session s2 = [Link]();
Alien a2 = [Link]([Link], 101); // Comes from L2 cache

⚖️ When Caching Helps vs Hurts


✅ Benefits:
Reduces database load.

Speeds up repeated reads.

Great for read-heavy applications.

⚠️ Risks:
May serve stale data if the DB changed between cache reads.

More complex to manage in high-concurrency systems.

Hibernate Notes 78
Needs careful invalidation and synchronization logic.

🧩 Cache Configuration Notes


To enable Level 2 cache, you must:

1. Add a cache provider (e.g., Ehcache, Caffeine).

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.

L2 cache = shared across sessions (optional).

Requires an external provider (Ehcache, Caffeine, etc.).

Hibernate uses JCache API to integrate with cache libraries.

Caching improves performance, but must be balanced against data


freshness.

📝 In short:
Hibernate’s L1 cache is automatic and session-scoped — it saves you from
repeated DB hits within the same session.

For shared caching between sessions, enable L2 cache using JCache-compatible


providers like Ehcache or Caffeine.

Hibernate Notes 79
Caching boosts performance but must be used carefully to avoid stale data or
unnecessary complexity.

⚡ Hibernate Query Language (HQL)


🎯 Goal
Understand what HQL (Hibernate Query Language) is, how it differs from SQL,
and how it allows developers to query Java objects (entities) rather than database
tables.

🧩 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.

Aspect SQL HQL

Works with Tables & columns Entities & properties

Output ResultSet (rows) Objects

Syntax style Database-centric Object-centric

Example entity student table Student class

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

Fetch all students SELECT * FROM student; FROM Student

Fetch student by SELECT * FROM student WHERE FROM Student WHERE


name name='John'; name='John'

SELECT * FROM student WHERE FROM Student WHERE


Fetch with condition
country='India'; country='India'

💡 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]();

// HQL example: fetch all students


Query<Student> query = [Link]("FROM Student", [Link]
s);
List<Student> students = [Link]();

for (Student s : students) {


[Link]([Link]() + " - " + [Link]());
}

[Link]();
[Link]();

✅ Hibernate internally converts this HQL into SQL before execution.


✅ You get Student objects, not raw DB rows.

Hibernate Notes 81
⚡ Why HQL Instead of SQL?
Advantage Description

Database HQL queries work across databases — Hibernate handles dialect


independence conversion.

Object-oriented You query entities and fields, not tables and columns.

Type-safe (with createQuery("FROM Student", [Link]) ensures compile-time


generics) safety.

JPA’s query language (JPQL) is based on HQL — learning HQL


Integrates with JPQL
means you already understand JPQL.

🧩 Native Queries (When Needed)


If you ever need raw SQL — for performance tuning or vendor-specific features —
you can use native queries:

Query query = [Link]("SELECT * FROM student", Studen


[Link]);
List<Student> students = [Link]();

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.

No SELECT * needed when fetching full entities.

Hibernate converts HQL → SQL behind the scenes.

Use native SQL only when Hibernate abstractions limit you.

📝 In short:
HQL lets you query objects, not tables.

It keeps your persistence layer clean, portable, and object-oriented — letting


Hibernate handle the SQL details for you.

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.

Instead of tables/columns, HQL works with entities (Java classes) and


properties (fields).

Hibernate converts HQL into SQL behind the scenes and returns objects rather
than raw ResultSet rows.

🧠 Why use HQL?


Keeps your code object-centric (you query Student / Laptop classes, not
student / laptop tables).

Improves portability — Hibernate handles DB dialects and SQL generation.

Cleaner API in Java: you get typed objects/lists directly from queries.

⚙️ SQL vs HQL (conceptual)


SQL (database-focused)

SELECT * FROM laptop WHERE brand = 'Apple';

HQL (entity-focused)

FROM Laptop WHERE brand = 'Apple'

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).

🧩 Basic HQL usage in Java (from demo)


Session session = [Link]();

// 1) Fetch by primary key (no HQL needed)


Laptop l1 = [Link]([Link], 3);

// 2) HQL: fetch all laptops


Query<Laptop> qAll = [Link]("from Laptop", [Link]);
List<Laptop> all = [Link]();

// 3) HQL with parameter (fetch by brand)


Query<Laptop> q = [Link]("from Laptop where brand = :brand",
[Link]);
[Link]("brand", "Apple");
List<Laptop> apples = [Link]();

The createQuery(...) call returns a Query object; use getResultList() to execute and
obtain a List of entities.

🧩 Notes & behaviors shown in the demo


HQL queries return mapped entity objects (e.g., List<Laptop> ), so you don’t
manually map ResultSet → objects as in JDBC.

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).

🧩 Native SQL (when needed)


If you need DB-specific features or raw SQL, you can use a native query:

Query<Laptop> nativeQ = [Link]("SELECT * FROM lapto


p", [Link]);

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 parameters ( :name ) to pass dynamic values safely into HQL.

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;

public int getLaptopId() {


return laptopId;
}

public void setLaptopId(int laptopId) {

Hibernate Notes 85
[Link] = laptopId;
}

public String getBrand() {


return brand;
}

public void setBrand(String brand) {


[Link] = brand;
}

public String getModel() {


return model;
}

public void setModel(String model) {


[Link] = model;
}

public String getColor() {


return color;
}

public void setColor(String color) {


[Link] = color;
}

public double getPrice() {


return price;
}

public void setPrice(double price) {


[Link] = price;
}

@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];

public class Main {


public static void main(String[] args) {
// Laptop l1 = new Laptop();
// [Link](4);
// [Link]("Apple");
// [Link]("Macbook Air");
// [Link](1300.00);
// [Link]("Grey");

SessionFactory sf = new Configuration().addAnnotatedClass([Link]


s).configure().buildSessionFactory();

Session session = [Link]();


// after the 4th value got updated in the db. As we are fetching no need to
use the transaction
// Transaction tx = [Link]();
// Fetching based on the PK
Laptop l1 = [Link]( [Link], 3 );
[Link]( l1 ); // Laptop{laptopId=3, brand='HP', model='HP Not
ebook', price=1900.0, color='Silver'}

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"

// To execute we need Query as it in interface


// Query query = [Link]( "from Laptop" ); // Here we are not
adding any filter
// // To execute
// List<Laptop> laptops = [Link](); // which gives list of value
s
// [Link]( laptops );
// [Laptop{laptopId=1, brand='Apple', model='Macbook Pro', price=2200.
0, color='Grey'}, Laptop{laptopId=2, brand='Dell', model='Dell XPS', price=180
0.0, color='Black'},
// Laptop{laptopId=3, brand='HP', model='HP Notebook', price=1900.0, c
olor='Silver'}, Laptop{laptopId=4, brand='Apple', model='Macbook Air', price=
1300.0, color='Grey'}]

// Fetching based on brand


Query query = [Link]( "from Laptop where brand = :brand"
);
[Link]( "brand", "Apple" );
// To execute
List<Laptop> laptops = [Link](); // which gives list of values
[Link]( laptops ); // [Laptop{laptopId=1, brand='Apple', model
='Macbook Pro', price=2200.0, color='Grey'}, Laptop{laptopId=4, brand='Appl
e', model='Macbook Air', price=1300.0, color='Grey'}]

// [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).

Use [Link](...) to build a Query object, then run getResultList() to get


results.

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).

⚙️ Parameters — positional vs named


Named parameters (clear & readable):

Query<Laptop> q = [Link]("from Laptop where brand = :bra


nd", [Link]);
[Link]("brand", "Asus");
List<Laptop> result = [Link]();

Positional parameters (ordinal): HQL supports ?1 , ?2 , ... — you must number


them.

Query q = [Link]("from Laptop where brand = ?1 and ram =


?2");

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.

You can also use LIKE for substring/text matching:

from Laptop where brand like :pattern

🧩 Selecting column(s) vs whole entity


1. Select whole entities (returns List<Laptop> ):

Query<Laptop> q = [Link]("from Laptop", [Link]);


List<Laptop> laptops = [Link]();

2. Select a single property (returns List<String> / List<Integer> depending on


property type):

Query<String> q = [Link]("select model from Laptop where


brand = :brand", [Link]);
[Link]("brand", "Asus");
List<String> models = [Link](); // e.g. ["ROG", "Strix"]

3. Select multiple properties (returns List<Object[]> — one array per row):

Query query = [Link]("select model, price from Laptop whe


re brand = :brand");
[Link]("brand", "Apple");
List<Object[]> rows = [Link]();

for (Object[] row : rows) {


[Link](row[0] + " " + row[1]); // model + price
}
// Output:
// Macbook Pro 2200.0
// Macbook Air 1300.0

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] ).

If you select multiple properties, expect List<Object[]> and iterate rows as


Object[] .

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

Fires SQL right


get() Eager Immediately Actual Entity
away

Fires SQL only


Proxy
load() Lazy On-demand when data is
(placeholder)
accessed

Lazy (modern Replacement


byId().getReference() On-demand Proxy
alternative) for load()

⚙️ Example: get() — Eager Fetch

Laptop laptop = [Link]([Link], 2);


[Link](laptop);

Immediately fires a SELECT query.

Even if you don’t use the returned object, the query still runs.

Data is fully fetched as soon as get() is called.

📊 Console output example


select * from laptop where id=2
Laptop{id=2, brand='Dell', ...}

✅ Use when:
You need the full entity right away (e.g., display or modify its fields immediately).

⚙️ Example: load() — Lazy Fetch (Deprecated)

Laptop laptop = [Link]([Link], 2);


[Link](laptop);

Returns a proxy object (a lightweight placeholder).

Does not hit the database until you access a property or print the object.

If you never access the data, no SQL is fired.

Deprecated in modern Hibernate — use byId().getReference() instead.

Hibernate Notes 92
📊 Behavior example
Laptop laptop = [Link]([Link], 2);
// No SQL yet
[Link]([Link]()); // SQL executes here

⚙️ Modern Alternative: byId().getReference()

Laptop laptop = [Link]([Link]).getReference(2);


[Link](laptop);

Works like load() — lazy fetch using proxy.

No query fired until you access a field.

Recommended replacement for load() in Hibernate 6+.

📊 Behavior example
Laptop laptop = [Link]([Link]).getReference(2);
// No SQL here
[Link]([Link]()); // SQL runs here

🔬 Comparison Summary
Feature get() load() / getReference()

Type Eager Lazy

Query Execution Immediately When accessed

Returns Actual entity Proxy object

If ID not found Returns null Throws ObjectNotFoundException

Use Case Need data right away Delay loading until needed

Deprecated? ❌ ✅( load() only)

✅ Best Practices
Use [Link]() when you know you’ll need the entity right away.

Use [Link]().getReference() when you want to delay fetching (lazy loading).

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.

load() (and now getReference() ) is lazy, fetching only when accessed.

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:

Cache Level Scope Default Notes

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.

⚙️ Step 1 — Add Dependencies


In [Link] , add:

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>

Ensure compatible versions with your Hibernate version.

⚙️ Step 2 — Configure Hibernate for Level 2 Cache


In [Link] (or properties ):

<property name="[Link].use_second_level_cache">true</property>
<property name="[Link].factory_class">
[Link]
</property>
<property name="[Link]">
[Link]
</property>

Enables Level 2 cache and sets EhCache as the provider.

⚙️ Step 3 — Annotate Entity


import [Link];
import [Link];
import [Link];

@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()...
}

@Cacheable tells Hibernate that this entity should be cached at Level 2.

⚙️ Step 4 — Fetch Data Across Sessions


Session session1 = [Link]();
Laptop l1 = [Link]([Link], 2); // Query hits DB
[Link]();

Session session2 = [Link]();


Laptop l2 = [Link]([Link], 2); // Query comes from Level 2 Cache
[Link]();

Behavior:

Without @Cacheable : SQL executes twice (once per session).

With @Cacheable & Level 2 cache: SQL executes once, second fetch comes
from cache.

📊 Console Example
select * from Laptop where laptopId=2 // First session
Laptop{...}

Laptop{...} // Second session (no SQL)

🔬 Key Points
Feature Level 1 Cache Level 2 Cache

Scope Session only SessionFactory (global)

Hibernate Notes 96
Feature Level 1 Cache Level 2 Cache

Query executed for same


No (within session) No (across sessions)
ID

Enabled by default? ✅ ❌
Annotation required ❌ ✅ @Cacheable

Frequent queries in single Share data between


Use case
transaction sessions

✅ Best Practices
Always use @Cacheable on entities you expect to reuse across sessions.

Level 2 cache is read-mostly friendly; avoid caching highly volatile entities.

Specify provider and version explicitly to avoid Maven dependency issues.

Monitor cache hit ratio to ensure cache is being used effectively.

📝 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

Common questions

Powered by AI

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 .

You might also like