Complete Layered Architecture
This is the same style of architecture as the reference image, but generated entirely from Mermaid code and rendered as an SVG diagram in the browser.
UITester.java"] SERVICE["2. Service Layer
EmployeeService.java
EmployeeServiceImpl.java"] FACTORY["3. Utility Layer
Factory.java"] DAO["4. DAO Layer
EmployeeDAO.java
EmployeeDAOImpl.java"] JPA["5. JPA / ORM Layer"] EMF["EntityManagerFactory"] EM["EntityManager"] ENTITY["EmployeeEntity.java
@Entity"] DB[("6. MySQL Database")] UI -->|"1. calls"| SERVICE SERVICE -->|"2. obtains/uses DAO"| FACTORY FACTORY -->|"3. creates"| DAO DAO -->|"4. obtains EMF"| FACTORY FACTORY -->|"5. provides"| EMF EMF -->|"6. creates"| EM EM -->|"7. manages"| ENTITY EM -->|"8. executes SQL"| DB UI -. "Carries EmployeeDTO data" .-> SERVICE SERVICE -. "Business rules" .-> DAO DAO -. "CRUD" .-> EM
How a JPA Program Starts
employeePU"] EMF["EntityManagerFactory"] EM1["EntityManager"] EM2["EntityManager"] XML --> P P --> PU PU --> EMF EMF --> EM1 EMF --> EM2
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("employeePU");
EntityManager em =
emf.createEntityManager();
EntityManagerFactory
A heavyweight factory associated with a persistence unit. It creates EntityManager instances.
EntityManager
Works with the persistence context and provides persist, find, merge, remove and query operations.
persistence.xml
Contains persistence-unit configuration such as provider, database properties and managed entity classes.
Java Entity → Database Table
@Entity"] MAPPING["JPA Mapping
@Table @Id @Column"] HIB["Hibernate"] TABLE[("employee table
employee_id
employee_name
role
salary
joining_date")] JAVA --> MAPPING --> HIB --> TABLE
@Entity
@Table(name = "employee")
public class Employee {
@Id
@Column(name = "employee_id")
private int employeeId;
@Column(name = "employee_name")
private String employeeName;
@Column(name = "role")
private String role;
private double salary;
@Temporal(TemporalType.DATE)
private Date joiningDate;
}
Complete CRUD Flow
| Operation | JPA API | What it means |
|---|---|---|
| Create | persist() | Makes a new entity managed and schedules insertion. |
| Read one | find() | Finds an entity using its primary-key value. |
| Read all | createQuery() | Runs JPQL and returns entities. |
| Update managed | Dirty checking | Change a managed entity; JPA detects the change at flush/commit. |
| Update detached | merge() | Copies detached state into a managed instance. |
| Delete | remove() | Marks a managed entity for deletion. |
Persist Operation
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
persist() does not mean "directly execute INSERT right now".
It makes the entity managed; Hibernate synchronizes changes with the database when the persistence
context is flushed, commonly at transaction commit.
Find Operation
Employee employee =
em.find(Employee.class, 1);
@Id, not an arbitrary column value.
JPQL Query
List<Employee> employees =
em.createQuery(
"SELECT e FROM Employee e",
Employee.class
).getResultList();
SELECT e FROM Employee e"] H["Hibernate"] SQL["SQL
SELECT ... FROM employee"] DB[("MySQL")] RESULT["List<Employee>"] JPQL --> H --> SQL --> DB --> H --> RESULT
JPQL talks about entities and their fields, not database tables directly.
Dirty Checking vs merge()
Managed entity
em.getTransaction().begin();
Employee e =
em.find(Employee.class, 1);
e.setSalary(75000);
em.getTransaction().commit();
No update() call is required. Hibernate detects the changed state during dirty checking.
Detached entity
em.getTransaction().begin();
em.merge(employee);
em.getTransaction().commit();
merge() copies the state into a managed instance.
Remove Operation
em.getTransaction().begin();
Employee employee =
em.find(Employee.class, id);
if (employee != null) {
em.remove(employee);
}
em.getTransaction().commit();
remove() should be applied to a managed entity.
A common safe pattern is find → remove → commit.
Entity Life Cycle
| State | Meaning | Typical transition |
|---|---|---|
| Transient | New Java object, not managed. | persist() → Managed |
| Managed | Tracked by the persistence context. | Dirty checking / remove / detach |
| Detached | Previously managed but no longer tracked. | merge() → Managed |
| Removed | Managed entity marked for deletion. | commit/flush → database DELETE |
DTO and Entity Flow
Request"] SERVICE["Service"] ENTITY["Employee Entity"] DAO["DAO"] EM["EntityManager"] DB[("Database")] RESP["EmployeeDTO
Response"] CLIENT --> REQ --> SERVICE SERVICE --> ENTITY --> DAO --> EM --> DB DB --> EM --> DAO --> ENTITY --> SERVICE --> RESP --> CLIENT
Transaction Flow
persist / merge / remove"] FLUSH["Persistence context flush"] SQL["Hibernate generates SQL"] COMMIT["commit()"] ROLLBACK["rollback()"] DB[("Database")] BEGIN --> OP --> FLUSH --> SQL --> DB DB --> COMMIT OP -. "Exception" .-> ROLLBACK ROLLBACK -. "undo transaction" .-> DB
try {
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
} catch (Exception e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
Who Does What?
| Component | Responsibility |
|---|---|
| UI / Tester | Starts the operation and displays the result. |
| DTO | Carries data between application layers. |
| Service | Contains business rules and orchestrates operations. |
| DAO | Contains persistence/database access logic. |
| Factory / Utility | Centralizes object creation/configuration. |
| EntityManagerFactory | Creates EntityManagers for a persistence unit. |
| EntityManager | Manages persistence context and JPA operations. |
| Entity | Java representation of persistent data. |
| Hibernate | JPA provider/ORM implementation that generates database interaction. |
| MySQL | Stores the persistent rows. |
What Actually Happens During a Create?
How the Files Connect
Every File — persistence.xml → UI Tester
This is the complete runnable version of the same Employee CRUD project. The code is intentionally kept in the same order in which the application is understood: Maven → persistence.xml → Entity → DTO → Utility → DAO → Service → UI Tester.
employee_db, change the username/password in
persistence.xml, then run UITester.java.
1. Project Structure
EmployeeManagement/
│
├── pom.xml
│
└── src/
└── main/
├── java/
│ └── com/example/
│ ├── entity/
│ │ └── EmployeeEntity.java
│ │
│ ├── dto/
│ │ └── EmployeeDTO.java
│ │
│ ├── dao/
│ │ ├── EmployeeDAO.java
│ │ └── EmployeeDAOImpl.java
│ │
│ ├── service/
│ │ ├── EmployeeService.java
│ │ └── EmployeeServiceImpl.java
│ │
│ └── utility/
│ ├── JPAUtility.java
│ └── Factory.java
│
│ └── UITester.java
│
└── resources/
└── META-INF/
└── persistence.xml
2. Database SQL
CREATE DATABASE employee_db;
USE employee_db;
CREATE TABLE employee (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(100) NOT NULL,
role VARCHAR(100),
salary DOUBLE,
joining_date DATE
);
3. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>EmployeeManagement</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JPA API -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<!-- Hibernate JPA implementation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.15.Final</version>
</dependency>
<!-- MySQL JDBC Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
</project>
4. persistence.xml
Location:
src/main/resources/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="employeePU">
<provider>
org.hibernate.jpa.HibernatePersistenceProvider
</provider>
<class>com.example.entity.EmployeeEntity</class>
<properties>
<property
name="javax.persistence.jdbc.driver"
value="com.mysql.cj.jdbc.Driver"/>
<property
name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/employee_db"/>
<property
name="javax.persistence.jdbc.user"
value="root"/>
<property
name="javax.persistence.jdbc.password"
value="root"/>
<property
name="hibernate.dialect"
value="org.hibernate.dialect.MySQL8Dialect"/>
<property
name="hibernate.show_sql"
value="true"/>
<property
name="hibernate.format_sql"
value="true"/>
</properties>
</persistence-unit>
</persistence>
employeePU here must exactly match
Persistence.createEntityManagerFactory("employeePU").
5. EmployeeEntity.java
package com.example.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;
@Entity
@Table(name = "employee")
public class EmployeeEntity {
@Id
@Column(name = "employee_id")
private int employeeId;
@Column(name = "employee_name")
private String employeeName;
@Column(name = "role")
private String role;
@Column(name = "salary")
private double salary;
@Temporal(TemporalType.DATE)
@Column(name = "joining_date")
private Date joiningDate;
public EmployeeEntity() {
}
public EmployeeEntity(
int employeeId,
String employeeName,
String role,
double salary,
Date joiningDate) {
this.employeeId = employeeId;
this.employeeName = employeeName;
this.role = role;
this.salary = salary;
this.joiningDate = joiningDate;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}
@Override
public String toString() {
return "EmployeeEntity{" +
"employeeId=" + employeeId +
", employeeName='" + employeeName + '\'' +
", role='" + role + '\'' +
", salary=" + salary +
", joiningDate=" + joiningDate +
'}';
}
}
6. EmployeeDTO.java
package com.example.dto;
import java.util.Date;
public class EmployeeDTO {
private int employeeId;
private String employeeName;
private String role;
private double salary;
private Date joiningDate;
public EmployeeDTO() {
}
public EmployeeDTO(
int employeeId,
String employeeName,
String role,
double salary,
Date joiningDate) {
this.employeeId = employeeId;
this.employeeName = employeeName;
this.role = role;
this.salary = salary;
this.joiningDate = joiningDate;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}
@Override
public String toString() {
return "EmployeeDTO{" +
"employeeId=" + employeeId +
", employeeName='" + employeeName + '\'' +
", role='" + role + '\'' +
", salary=" + salary +
", joiningDate=" + joiningDate +
'}';
}
}
7. JPAUtility.java
This class centralizes the EntityManagerFactory and EntityManager creation.
package com.example.utility;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public final class JPAUtility {
private static final EntityManagerFactory EMF =
Persistence.createEntityManagerFactory("employeePU");
private JPAUtility() {
// Utility class - do not create objects.
}
public static EntityManager getEntityManager() {
return EMF.createEntityManager();
}
public static EntityManagerFactory getEntityManagerFactory() {
return EMF;
}
public static void close() {
if (EMF.isOpen()) {
EMF.close();
}
}
}
8. Factory.java
The Factory hides DAO implementation creation from the Service layer.
package com.example.utility;
import com.example.dao.EmployeeDAO;
import com.example.dao.EmployeeDAOImpl;
public final class Factory {
private Factory() {
// Utility class - do not create objects.
}
public static EmployeeDAO getEmployeeDAO() {
return new EmployeeDAOImpl();
}
}
9. EmployeeDAO.java
package com.example.dao;
import com.example.entity.EmployeeEntity;
import java.util.List;
public interface EmployeeDAO {
void save(EmployeeEntity employee);
EmployeeEntity findById(int id);
List<EmployeeEntity> findAll();
void update(EmployeeEntity employee);
void delete(int id);
}
10. EmployeeDAOImpl.java — Complete CRUD
package com.example.dao;
import com.example.entity.EmployeeEntity;
import com.example.utility.JPAUtility;
import javax.persistence.EntityManager;
import java.util.List;
public class EmployeeDAOImpl implements EmployeeDAO {
@Override
public void save(EmployeeEntity employee) {
EntityManager em =
JPAUtility.getEntityManager();
try {
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
} catch (RuntimeException e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
}
@Override
public EmployeeEntity findById(int id) {
EntityManager em =
JPAUtility.getEntityManager();
try {
return em.find(EmployeeEntity.class, id);
} finally {
em.close();
}
}
@Override
public List<EmployeeEntity> findAll() {
EntityManager em =
JPAUtility.getEntityManager();
try {
return em.createQuery(
"SELECT e FROM EmployeeEntity e",
EmployeeEntity.class
).getResultList();
} finally {
em.close();
}
}
@Override
public void update(EmployeeEntity employee) {
EntityManager em =
JPAUtility.getEntityManager();
try {
em.getTransaction().begin();
em.merge(employee);
em.getTransaction().commit();
} catch (RuntimeException e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
}
@Override
public void delete(int id) {
EntityManager em =
JPAUtility.getEntityManager();
try {
em.getTransaction().begin();
EmployeeEntity employee =
em.find(EmployeeEntity.class, id);
if (employee != null) {
em.remove(employee);
}
em.getTransaction().commit();
} catch (RuntimeException e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
}
}
11. EmployeeService.java
package com.example.service;
import com.example.dto.EmployeeDTO;
import java.util.List;
public interface EmployeeService {
void createEmployee(EmployeeDTO dto);
EmployeeDTO getEmployee(int id);
List<EmployeeDTO> getAllEmployees();
void updateEmployee(EmployeeDTO dto);
void deleteEmployee(int id);
}
12. EmployeeServiceImpl.java
package com.example.service;
import com.example.dao.EmployeeDAO;
import com.example.dto.EmployeeDTO;
import com.example.entity.EmployeeEntity;
import com.example.utility.Factory;
import java.util.ArrayList;
import java.util.List;
public class EmployeeServiceImpl
implements EmployeeService {
private final EmployeeDAO employeeDAO;
public EmployeeServiceImpl() {
employeeDAO =
Factory.getEmployeeDAO();
}
@Override
public void createEmployee(EmployeeDTO dto) {
validate(dto);
EmployeeEntity employee =
toEntity(dto);
employeeDAO.save(employee);
}
@Override
public EmployeeDTO getEmployee(int id) {
EmployeeEntity employee =
employeeDAO.findById(id);
if (employee == null) {
return null;
}
return toDTO(employee);
}
@Override
public List<EmployeeDTO> getAllEmployees() {
List<EmployeeEntity> entities =
employeeDAO.findAll();
List<EmployeeDTO> result =
new ArrayList<>();
for (EmployeeEntity entity : entities) {
result.add(toDTO(entity));
}
return result;
}
@Override
public void updateEmployee(EmployeeDTO dto) {
validate(dto);
EmployeeEntity employee =
toEntity(dto);
employeeDAO.update(employee);
}
@Override
public void deleteEmployee(int id) {
EmployeeEntity employee =
employeeDAO.findById(id);
if (employee == null) {
throw new IllegalArgumentException(
"Employee with ID " + id +
" does not exist."
);
}
employeeDAO.delete(id);
}
private void validate(EmployeeDTO dto) {
if (dto == null) {
throw new IllegalArgumentException(
"Employee data cannot be null."
);
}
if (dto.getEmployeeId() <= 0) {
throw new IllegalArgumentException(
"Employee ID must be positive."
);
}
if (dto.getEmployeeName() == null ||
dto.getEmployeeName().trim().isEmpty()) {
throw new IllegalArgumentException(
"Employee name is required."
);
}
if (dto.getSalary() < 0) {
throw new IllegalArgumentException(
"Salary cannot be negative."
);
}
}
private EmployeeEntity toEntity(
EmployeeDTO dto) {
return new EmployeeEntity(
dto.getEmployeeId(),
dto.getEmployeeName(),
dto.getRole(),
dto.getSalary(),
dto.getJoiningDate()
);
}
private EmployeeDTO toDTO(
EmployeeEntity entity) {
return new EmployeeDTO(
entity.getEmployeeId(),
entity.getEmployeeName(),
entity.getRole(),
entity.getSalary(),
entity.getJoiningDate()
);
}
}
13. UITester.java — Complete CREATE / READ / UPDATE / DELETE
package com.example;
import com.example.dto.EmployeeDTO;
import com.example.service.EmployeeService;
import com.example.service.EmployeeServiceImpl;
import com.example.utility.JPAUtility;
import java.util.Date;
import java.util.List;
public class UITester {
public static void main(String[] args) {
EmployeeService service =
new EmployeeServiceImpl();
try {
// =================================================
// 1. CREATE
// =================================================
System.out.println(
"\\n========== CREATE =========="
);
EmployeeDTO employee =
new EmployeeDTO(
1001,
"Rahul",
"Java Developer",
50000.00,
new Date()
);
service.createEmployee(employee);
System.out.println(
"Employee created successfully!"
);
// =================================================
// 2. READ ONE
// =================================================
System.out.println(
"\\n========== READ ONE =========="
);
EmployeeDTO found =
service.getEmployee(1001);
if (found != null) {
System.out.println(
"Employee found:"
);
System.out.println(found);
} else {
System.out.println(
"Employee not found."
);
}
// =================================================
// 3. READ ALL
// =================================================
System.out.println(
"\\n========== READ ALL =========="
);
List<EmployeeDTO> employees =
service.getAllEmployees();
for (EmployeeDTO dto : employees) {
System.out.println(dto);
}
// =================================================
// 4. UPDATE
// =================================================
System.out.println(
"\\n========== UPDATE =========="
);
EmployeeDTO employeeToUpdate =
service.getEmployee(1001);
if (employeeToUpdate != null) {
employeeToUpdate.setSalary(
75000.00
);
employeeToUpdate.setRole(
"Senior Java Developer"
);
service.updateEmployee(
employeeToUpdate
);
System.out.println(
"Employee updated successfully!"
);
}
// =================================================
// 5. READ AFTER UPDATE
// =================================================
System.out.println(
"\\n========== READ AFTER UPDATE =========="
);
EmployeeDTO updated =
service.getEmployee(1001);
System.out.println(updated);
// =================================================
// 6. DELETE
// =================================================
System.out.println(
"\\n========== DELETE =========="
);
service.deleteEmployee(1001);
System.out.println(
"Employee deleted successfully!"
);
// =================================================
// 7. VERIFY DELETE
// =================================================
System.out.println(
"\\n========== VERIFY DELETE =========="
);
EmployeeDTO deleted =
service.getEmployee(1001);
if (deleted == null) {
System.out.println(
"Employee does not exist anymore."
);
} else {
System.out.println(
"Employee still exists: " +
deleted
);
}
} catch (Exception e) {
System.err.println(
"Operation failed: " +
e.getMessage()
);
e.printStackTrace();
} finally {
// Close the application-level
// EntityManagerFactory.
JPAUtility.close();
}
}
}
14. What the UI Tester actually triggers
15. Expected Console Output
========== CREATE ==========
Employee created successfully!
========== READ ONE ==========
Employee found:
EmployeeDTO{
employeeId=1001,
employeeName='Rahul',
role='Java Developer',
salary=50000.0,
...
}
========== READ ALL ==========
EmployeeDTO{
employeeId=1001,
employeeName='Rahul',
role='Java Developer',
salary=50000.0,
...
}
========== UPDATE ==========
Employee updated successfully!
========== READ AFTER UPDATE ==========
EmployeeDTO{
employeeId=1001,
employeeName='Rahul',
role='Senior Java Developer',
salary=75000.0,
...
}
========== DELETE ==========
Employee deleted successfully!
========== VERIFY DELETE ==========
Employee does not exist anymore.
UITester → Service → Factory → DAO → JPAUtility → EntityManagerFactory → EntityManager → Hibernate → MySQL.
One Place to See All CRUD Methods
public class EmployeeDAOImpl implements EmployeeDAO {
private EntityManagerFactory emf;
public EmployeeDAOImpl() {
emf = Persistence
.createEntityManagerFactory("employeePU");
}
// CREATE
public void save(Employee employee) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
} catch (Exception e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
}
// READ ONE
public Employee findById(int id) {
EntityManager em = emf.createEntityManager();
try {
return em.find(Employee.class, id);
} finally {
em.close();
}
}
// READ ALL
public List<Employee> findAll() {
EntityManager em = emf.createEntityManager();
try {
return em.createQuery(
"SELECT e FROM Employee e",
Employee.class
).getResultList();
} finally {
em.close();
}
}
// UPDATE
public void update(Employee employee) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
em.merge(employee);
em.getTransaction().commit();
} catch (Exception e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
}
// DELETE
public void delete(int id) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
Employee employee =
em.find(Employee.class, id);
if (employee != null) {
em.remove(employee);
}
em.getTransaction().commit();
} catch (Exception e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
}
}
Things You Must Not Mix Up
JPA vs Hibernate?
JPA is the specification/API. Hibernate is an implementation/provider of JPA.
EntityManagerFactory vs EntityManager?
EntityManagerFactory creates EntityManagers. EntityManager works with entities and the persistence context.
Does EntityManager have update()?
No. Managed entities are normally updated through dirty checking. Detached state can be re-associated through merge().
Why find() before remove()?
remove() expects a managed entity. find() obtains the entity through the current persistence context.
What does merge() return?
merge() returns a managed instance containing the merged state. Do not assume the original detached object becomes managed.
What is dirty checking?
Hibernate tracks managed entities and detects changes to their state, generating SQL during flush when required.
Where is persistence.xml?
META-INF/persistence.xml on the classpath.
What is persistence-unit name?
The logical configuration name used to bootstrap the EntityManagerFactory.
What happens if find() cannot locate the ID?
For EntityManager.find(), the result is null when no matching entity is found.
Why begin/commit?
Database-changing operations are performed within a transaction in this resource-local JPA example.
Learn This Sequence
begin → persist → commitfind()JPQL → getResultList()managed → dirty checkingmerge()find → remove → commit50 Real JPA Interview Scenarios
Practice every question as Situation → Root cause → JPA concept → Fix → Interview answer. These are tied directly to the Employee CRUD project.
01. persist() succeeds but no row appears
What is happening: Check that a transaction was started and committed. persist() makes the entity managed; database synchronization happens during flush/commit.
What would you do: begin → persist → commit
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
02. persist() is called without begin()
What is happening: Resource-local JPA write operations require an active transaction.
What would you do: Start the transaction before persist().
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
03. find() returns null
What is happening: No entity exists for that primary-key value. find() normally returns null when nothing is found.
What would you do: Check the ID and database row.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
04. find() is called twice with the same EntityManager
What is happening: The persistence context is the first-level cache, so the same managed entity can be reused.
What would you do: Same EntityManager → same persistence context.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
05. find() uses two EntityManagers
What is happening: Each EntityManager has its own persistence context.
What would you do: Do not assume first-level cache is shared.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
06. Salary changes but no update() is called
What is happening: A managed entity is tracked by dirty checking.
What would you do: find → modify → commit.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
07. Salary changes after EntityManager.close()
What is happening: The entity is detached and the old persistence context no longer tracks it.
What would you do: Merge the state in a new persistence context.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
08. merge() is called but the original object is still detached
What is happening: merge copies state into a managed instance and returns that managed instance.
What would you do: Capture EmployeeEntity managed = em.merge(detached).
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
09. merge() return value is ignored
What is happening: Later changes to the original detached object are not automatically tracked.
What would you do: Continue with the object returned by merge().
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
10. remove() fails for an object
What is happening: remove requires a managed entity in the current persistence context.
What would you do: find → remove → commit.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
11. remove() is called without a transaction
What is happening: A database-changing operation is outside the required transaction.
What would you do: begin → remove → commit.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
12. An exception occurs halfway through a transaction
What is happening: The incomplete transaction should be rolled back.
What would you do: Rollback if active, then propagate the exception.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
13. commit() throws an exception
What is happening: The persistence operation did not complete successfully.
What would you do: Do not swallow the exception; handle rollback appropriately.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
14. EntityManagerFactory is created in every DAO method
What is happening: EntityManagerFactory is heavyweight and should not be repeatedly created.
What would you do: Create one application-level factory per persistence unit.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
15. EntityManager is never closed
What is happening: Persistence resources remain open unnecessarily.
What would you do: Close it in finally or an appropriate resource-management pattern.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
16. EntityManagerFactory is never closed
What is happening: Application-level persistence resources are not released.
What would you do: Close it during application shutdown.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
17. persistence.xml cannot be found
What is happening: It is not available on the runtime classpath at META-INF/persistence.xml.
What would you do: Place it under src/main/resources/META-INF.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
18. Persistence-unit name is wrong
What is happening: The Java name passed to createEntityManagerFactory must match the XML name.
What would you do: Make employeePU match exactly.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
19. EmployeeEntity is not detected
What is happening: The entity may not be registered in the persistence unit.
What would you do: Register its fully qualified class when explicit registration is used.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
20. Hibernate says the entity has no identifier
What is happening: The entity lacks a valid primary-key mapping.
What would you do: Add @Id to the identifier.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
21. Java field and DB column names differ
What is happening: ORM needs an explicit mapping when names do not match.
What would you do: Use @Column(name = "employee_id").
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
22. Hibernate targets the wrong table
What is happening: Entity-to-table mapping disagrees with the schema.
What would you do: Verify @Table(name = "employee").
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
23. JPQL uses SELECT * FROM employee
What is happening: JPQL is entity-oriented, unlike SQL.
What would you do: Use SELECT e FROM EmployeeEntity e.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
24. JPQL uses employee_name
What is happening: JPQL refers to entity attributes, not physical column names.
What would you do: Use e.employeeName.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
25. getResultList() returns an empty list
What is happening: The query succeeded but no matching entities were found.
What would you do: An empty list is normal and is not null.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
26. getSingleResult() finds multiple rows
What is happening: A single-result API cannot represent multiple results.
What would you do: Use getResultList or make the query uniquely constrained.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
27. DTO is passed directly to DAO
What is happening: DTO and Entity have different responsibilities.
What would you do: Map DTO → Entity before persistence.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
28. Why not expose Entity directly to UI?
What is happening: DTOs provide an API boundary and avoid leaking persistence details.
What would you do: Use request/response DTOs.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
29. Business validation is inside DAO
What is happening: DAO should focus on persistence access.
What would you do: Keep business rules in Service.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
30. Service contains all JPQL
What is happening: Business logic becomes coupled to persistence implementation.
What would you do: Keep database access in DAO.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
31. Factory creates a new DAO for every request
What is happening: A lightweight DAO can be recreated; the heavyweight EMF should not be.
What would you do: Separate DAO lifecycle from JPA infrastructure lifecycle.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
32. Two EntityManagers modify the same employee
What is happening: They have separate persistence contexts.
What would you do: Managed state is not shared automatically.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
33. A managed entity is changed twice before commit
What is happening: Dirty checking synchronizes the managed state at flush.
What would you do: Do not treat every setter as immediate SQL.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
34. persist() is called for an existing ID
What is happening: persist is intended for new entity state; an existing key can cause an INSERT constraint failure.
What would you do: Use the lifecycle operation appropriate to the state.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
35. merge() is called on a new object
What is happening: merge is not strictly update-only; it merges state into a managed instance and can result in insertion.
What would you do: Explain merge as state synchronization.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
36. merge() then the original object is modified
What is happening: The original remains detached.
What would you do: Use the managed instance returned by merge().
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
37. clear() then a managed object is modified
What is happening: clear detaches all entities from that persistence context.
What would you do: Those objects are no longer automatically tracked.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
38. Lazy data is accessed after EntityManager.close()
What is happening: Unfetched lazy state may need an open persistence context.
What would you do: Load required data inside the correct persistence boundary.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
39. A Java reference is assumed to be automatically managed
What is happening: Management belongs to the persistence context, not the Java reference.
What would you do: Know transient, managed, detached and removed states.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
40. SQL appears before commit
What is happening: Hibernate can flush before commit when synchronization is required.
What would you do: Flush and commit are related but different concepts.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
41. Database-generated state is not visible in Java
What is happening: Database state and in-memory state can differ.
What would you do: Understand refresh when current DB state is needed.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
42. External SQL changes a managed row
What is happening: The persistence context may still contain older state.
What would you do: Use refresh when appropriate.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
43. One business operation performs several DAO calls
What is happening: Separate transactions can partially commit a business operation.
What would you do: Use one appropriate transaction boundary for the use case.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
44. Delete employee and insert audit record must both succeed
What is happening: The two changes should be atomic.
What would you do: Put both in the same transaction boundary.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
45. Works locally but fails elsewhere
What is happening: Environment/configuration may differ.
What would you do: Check JDBC URL, DB, credentials, driver, port and schema.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
46. Hibernate cannot connect to MySQL
What is happening: The issue may be connectivity rather than entity mapping.
What would you do: Check MySQL status, URL, credentials, driver and port.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
47. Table or column does not exist
What is happening: Entity mapping and physical schema disagree.
What would you do: Check @Table, @Column and the actual schema.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
48. One EntityManager is created per tiny operation
What is happening: Related work can end up in different persistence contexts and transactions.
What would you do: Choose a sensible persistence-context/transaction scope.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
49. Explain UI-to-database flow
What is happening: UI calls Service; Service validates/maps; DAO uses EntityManager; Hibernate translates JPA operations into SQL; MySQL persists data.
What would you do: UI → Service → DAO → EntityManager → Hibernate → MySQL.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
50. Why use layered architecture?
What is happening: Each layer has a focused responsibility, reducing coupling and improving maintenance and testing.
What would you do: UI interaction; Service business logic; DAO persistence; Utility infrastructure.
Follow-up: Explain which entity state and persistence-context/transaction boundary are involved, then show the smallest code change that fixes the problem.
Rapid-Fire Coding Drill
// Find employee 1001.
// Increase salary if found.
// No update() call is required because the entity is managed.
em.getTransaction().begin();
EmployeeEntity employee =
em.find(EmployeeEntity.class, 1001);
if (employee != null) {
employee.setSalary(
employee.getSalary() + 10000
);
}
em.getTransaction().commit();