Top Interview Questions
Java Persistence API (JPA) is a specification in the Java Enterprise Edition (Java EE) platform that provides a standard framework for object-relational mapping (ORM). ORM allows developers to map Java objects to relational database tables and vice versa. JPA simplifies database operations and abstracts the low-level complexities of JDBC (Java Database Connectivity), making it easier to manage data persistence in Java applications.
Introduced as part of Java EE 5 in 2006, JPA is not an implementation itself but a specification. Implementations such as Hibernate, EclipseLink, OpenJPA, and DataNucleus provide the actual functionality. JPA aims to provide a POJO-based persistence model, meaning entities can be simple Java classes without needing to extend specific base classes.
Before JPA, Java applications relied heavily on JDBC for database operations. While JDBC is powerful, it has several limitations:
Verbose Code: Every query requires manual handling of SQL statements, result sets, and exception handling.
Database Dependence: SQL queries may be database-specific, reducing portability.
Object-Relational Impedance Mismatch: Mapping Java objects to relational tables manually is error-prone and tedious.
Transaction Management Complexity: Managing transactions manually with JDBC is cumbersome.
JPA addresses these issues by providing:
Entity-based persistence: Java classes represent database tables.
Database independence: JPQL (Java Persistence Query Language) abstracts the SQL syntax.
Automatic mapping: JPA handles the mapping between objects and database tables.
Transaction management support: Works seamlessly with Java Transaction API (JTA) and local transactions.
Entity:
An entity is a lightweight, persistent domain object representing a table in a relational database. Each entity instance corresponds to a row in the table.
Example:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Employee {
@Id
private Long id;
private String name;
private String department;
// Getters and Setters
}
Here, the Employee class is an entity, and @Id marks the primary key.
Entity Manager:
The EntityManager interface is the core of JPA, responsible for managing entity lifecycle, performing CRUD operations, and executing queries.
Example:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee emp = new Employee();
emp.setId(1L);
emp.setName("John Doe");
emp.setDepartment("IT");
em.persist(emp); // Save entity
em.getTransaction().commit();
em.close();
Persistence Unit:
A persistence unit is a logical grouping of entities and configuration metadata, defined in persistence.xml. It includes database connection details and entity classes.
Example:
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" version="3.0">
<persistence-unit name="myPU">
<class>com.example.Employee</class>
<properties>
<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="jakarta.persistence.jdbc.user" value="root"/>
<property name="jakarta.persistence.jdbc.password" value="password"/>
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
</properties>
</persistence-unit>
</persistence>
JPQL (Java Persistence Query Language):
JPQL is an object-oriented query language similar to SQL but operates on entity objects rather than database tables.
Example:
List<Employee> employees = em.createQuery("SELECT e FROM Employee e WHERE e.department = :dept", Employee.class)
.setParameter("dept", "IT")
.getResultList();
Entity Relationships:
JPA supports mapping relationships between entities using annotations:
One-to-One (@OneToOne): Each entity instance is associated with exactly one instance of another entity.
One-to-Many (@OneToMany): One entity relates to multiple instances of another entity.
Many-to-One (@ManyToOne): Many entities relate to a single entity.
Many-to-Many (@ManyToMany): Multiple instances of entities relate to multiple instances of another entity.
Example:
@OneToMany(mappedBy = "department")
private List<Employee> employees;
Entity Lifecycle:
JPA defines states for entities:
Transient: New instance, not associated with the persistence context.
Persistent: Managed by EntityManager and synchronized with the database.
Detached: Previously persistent but currently unmanaged.
Removed: Scheduled for deletion from the database.
Caching:
JPA provides first-level (per EntityManager) and second-level (shared across EntityManagerFactory) caching for performance optimization.
Productivity: Reduces boilerplate code for database operations.
Portability: Works with multiple relational databases without changing Java code.
Maintainability: Clear separation between business logic and persistence logic.
Performance: Supports caching, batch operations, and lazy loading.
Standardization: Being a Java standard, it allows switching implementations (e.g., Hibernate, EclipseLink) with minimal changes.
JPA provides various annotations to simplify mapping and configuration:
@Entity: Marks a class as a JPA entity.
@Table: Specifies the table name in the database.
@Id: Marks the primary key field.
@GeneratedValue: Defines primary key generation strategy.
@Column: Customizes column mapping.
@Transient: Marks a field to be ignored by persistence.
@Embedded & @Embeddable: Support embedding a value object inside an entity.
JPA supports two types of transactions:
Resource-local transactions: Managed locally using EntityManager.getTransaction().
JTA (Java Transaction API) transactions: Managed by the application server, suitable for distributed transactions.
Example:
em.getTransaction().begin();
em.persist(emp);
em.getTransaction().commit();
Criteria API: Type-safe query creation using Java objects instead of string-based JPQL.
Named Queries: Predefined queries stored at the entity or XML level.
Lazy vs Eager Loading: Controls when related entities are loaded.
Cascade Operations: Automatically propagate operations (persist, remove) to related entities.
Optimistic Locking: Prevents lost updates in concurrent transactions using @Version.
While JPA is a specification, several popular implementations exist:
Hibernate: Most widely used; supports advanced ORM features.
EclipseLink: Reference implementation of JPA.
OpenJPA: Apache project, compatible with JPA standard.
DataNucleus: Provides support for various datastores including RDBMS and NoSQL.
Answer:
JPA (Java Persistence API) is a Java specification used to persist, read, update, and delete data from relational databases using Java objects.
It provides Object–Relational Mapping (ORM)
It is only a specification, not an implementation
Implementations include:
Hibernate
EclipseLink
OpenJPA
π JPA allows developers to work with Java objects instead of SQL queries.
Answer:
ORM is a technique that maps:
Java classes → Database tables
Java objects → Table rows
Java fields → Table columns
Example:
@Entity
class Employee {
@Id
private int id;
private String name;
}
Maps to:
EMPLOYEE (ID, NAME)
ORM reduces boilerplate JDBC code and improves productivity.
| JPA | Hibernate |
|---|---|
| Specification | Implementation |
| Defined by Java | Provided by Red Hat |
| Standard API | Vendor-specific features |
| Portable | Not fully portable |
π Hibernate implements JPA and also provides extra features.
Answer:
An Entity is a Java class mapped to a database table.
Rules:
Must be annotated with @Entity
Must have a primary key (@Id)
Must have a default constructor
Example:
@Entity
public class Student {
@Id
private int id;
private String name;
}
@Id annotation?Answer:
@Id is used to define the primary key of an entity.
Example:
@Id
private Long empId;
Every entity must have exactly one primary key.
@GeneratedValue?Answer:
Used to auto-generate primary key values.
Strategies:
AUTO
IDENTITY
SEQUENCE
TABLE
Example:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
Answer:
Persistence means storing Java object data permanently in a database and retrieving it later.
JPA handles persistence automatically using ORM.
EntityManager?Answer:
EntityManager is the main interface used to interact with the database.
Functions:
Persist entity
Find entity
Remove entity
Update entity
Example:
entityManager.persist(employee);
persistence.xml?Answer:
It is a configuration file that:
Defines database connection
Specifies JPA provider
Declares persistence unit
Location:
META-INF/persistence.xml
Answer:
A persistence unit defines:
Database connection
Entity classes
JPA provider
Example:
<persistence-unit name="myPU">
Answer:
Annotations define how Java classes map to database tables.
Common annotations:
@Entity
@Table
@Id
@Column
@Transient
@OneToOne
@OneToMany
@ManyToOne
@Table annotation?Answer:
Used to specify the table name.
@Entity
@Table(name="EMP_TABLE")
public class Employee {}
@Column annotation?Answer:
Maps a Java field to a table column.
@Column(name="EMP_NAME", nullable=false)
private String name;
@Transient?Answer:
Fields marked with @Transient are not persisted to the database.
@Transient
private int tempValue;
Answer:
An entity goes through these states:
New – Not associated with DB
Managed – Associated with persistence context
Detached – No longer managed
Removed – Marked for deletion
Answer:
A persistence context is a cache that stores managed entities.
Maintains entity uniqueness
Automatically synchronizes changes with DB
Answer:
JPQL (Java Persistence Query Language) is:
Object-oriented query language
Works on entity objects, not tables
Example:
SELECT e FROM Employee e WHERE e.salary > 50000
| JPQL | SQL |
|---|---|
| Uses entity names | Uses table names |
| Object-oriented | Database-oriented |
| Portable | DB-specific |
find() method?Answer:
Used to retrieve an entity by primary key.
Employee e = entityManager.find(Employee.class, 1);
persist()?Answer:
Stores a new entity into the database.
entityManager.persist(employee);
merge()?Answer:
Used to update detached entities.
entityManager.merge(employee);
remove()?Answer:
Deletes an entity from the database.
entityManager.remove(employee);
Answer:
JPA supports relationships between entities:
@OneToOne
@OneToMany
@ManyToOne
@ManyToMany
@ManyToOne?Answer:
Many entities are related to one entity.
Example:
@ManyToOne
@JoinColumn(name="dept_id")
private Department department;
@OneToMany?Answer:
One entity is related to many entities.
@OneToMany(mappedBy="department")
private List<Employee> employees;
Answer:
Defines when data is loaded.
EAGER – Load immediately
LAZY – Load when required
@OneToMany(fetch = FetchType.LAZY)
Answer:
Defines how operations propagate.
Common types:
PERSIST
MERGE
REMOVE
ALL
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn?Answer:
Defines the foreign key column.
@JoinColumn(name="dept_id")
Answer:
A primary key uniquely identifies each row in a table.
In JPA, it is defined using @Id.
Answer:
Reduces boilerplate JDBC code
Database independent
Easy CRUD operations
Object-oriented approach
Integrates well with Spring
@MappedSuperclass?Answer:
@MappedSuperclass is used when you want common fields to be shared across multiple entities.
No table is created for it
Fields are mapped to child entity tables
@MappedSuperclass
public class BaseEntity {
@Id
private Long id;
private LocalDateTime createdDate;
}
@Entity and @MappedSuperclass?| @Entity | @MappedSuperclass |
|---|---|
| Table is created | No table created |
| Can be queried | Cannot be queried |
| Independent entity | Only base class |
@Embeddable?Answer:
Used to represent a value object whose fields are embedded into an entity.
@Embeddable
class Address {
private String city;
private String pincode;
}
@Embedded?Answer:
Used to embed an @Embeddable class into an entity.
@Embedded
private Address address;
@Embedded and @OneToOne?| @Embedded | @OneToOne |
|---|---|
| Same table | Separate table |
| No identity | Has identity |
| Value object | Entity |
@Enumerated?Answer:
Used to persist Java enums.
@Enumerated(EnumType.STRING)
private Status status;
Types:
ORDINAL (stores index – risky)
STRING (stores name – recommended)
@Temporal?Answer:
Maps Java Date to DB types.
@Temporal(TemporalType.DATE)
private Date dob;
@NamedQuery?Answer:
Predefined JPQL queries defined at entity level.
@NamedQuery(
name="Employee.findAll",
query="SELECT e FROM Employee e"
)
Advantages:
Better performance
Centralized queries
Answer:
SQL queries written directly.
entityManager
.createNativeQuery("SELECT * FROM EMP")
.getResultList();
Used when JPQL is insufficient.
| JPQL | Native |
|---|---|
| Portable | DB specific |
| Uses entities | Uses tables |
| Safer | Faster sometimes |
Answer:
Data is loaded only when accessed.
@OneToMany(fetch = FetchType.LAZY)
Improves performance.
Answer:
Data is loaded immediately with the entity.
@ManyToOne(fetch = FetchType.EAGER)
Can impact performance if overused.
Answer:
Occurs when:
One query loads parent
Multiple queries load child entities
Solution:
JOIN FETCH
Entity Graphs
JOIN FETCH?Answer:
Fetches related entities in a single query.
SELECT e FROM Employee e JOIN FETCH e.department
Answer:
Defines fetch plans dynamically.
@EntityGraph(attributePaths = {"department"})
Avoids N+1 issue.
Answer:
Uses versioning to handle concurrent updates.
@Version
private int version;
Fails update if data is modified by another user.
Answer:
Locks DB rows to prevent others from updating.
LockModeType.PESSIMISTIC_WRITE
| Optimistic | Pessimistic |
|---|---|
| No DB lock | DB lock |
| Better performance | Slower |
| Uses version | Uses locks |
@Version?Answer:
Used for optimistic locking.
@Version
private Long version;
Answer:
JPA automatically detects entity changes and updates DB without explicit update query.
Answer:
Flush synchronizes persistence context with database.
entityManager.flush();
| Flush | Commit |
|---|---|
| Syncs data | Saves transaction |
| Does not end transaction | Ends transaction |
detach()?Answer:
Removes entity from persistence context.
entityManager.detach(entity);
clear()?Answer:
Clears entire persistence context.
entityManager.clear();
refresh()?Answer:
Reloads entity state from database.
entityManager.refresh(entity);
@OrderBy?Answer:
Orders collection results.
@OrderBy("name ASC")
@OrderColumn?Answer:
Maintains list order using index column.
@SecondaryTable?Answer:
Maps entity to multiple tables.
@SecondaryTable(name="EMP_DETAILS")
@Inheritance?Answer:
Used for entity inheritance.
Strategies:
SINGLE_TABLE
JOINED
TABLE_PER_CLASS
| Strategy | Tables | Performance |
|---|---|---|
| SINGLE_TABLE | One | Fast |
| JOINED | Multiple | Slower |
| TABLE_PER_CLASS | Many | Medium |
@DiscriminatorColumn?Answer:
Identifies subclass type in inheritance.
@SQLDelete?Answer:
Used for soft delete.
@SQLDelete(sql="UPDATE emp SET deleted=true WHERE id=?")
Answer:
Marks record as deleted without removing it physically.
@Where?Answer:
Filters entity results.
@Where(clause="deleted=false")
Answer:
Lifecycle methods:
@PrePersist
@PostPersist
@PreUpdate
@PostRemove
@PrePersist?Answer:
Executed before entity is saved.
@PrePersist
void beforeSave(){}
@PostLoad?Answer:
Executed after entity is loaded.
@Basic?Answer:
Default mapping for simple fields.
@Access?Answer:
Defines access type:
FIELD
PROPERTY
Answer:
Clean architecture
Reduced SQL dependency
Easy maintenance
Scalable enterprise applications
JPA (Java Persistence API) is a Java specification that provides a standard way to map Java objects to relational database tables and manage relational data in Java applications.
Eliminates boilerplate JDBC code
Provides ORM (Object Relational Mapping)
Vendor-independent (Hibernate, EclipseLink, OpenJPA)
Integrates easily with Spring and Spring Boot
Supports caching, transactions, and relationships
JPA itself is not an implementation, it is only a specification.
| JPA | Hibernate |
|---|---|
| Specification | Implementation |
| Part of Java EE/Jakarta EE | Third-party framework |
| Defines annotations & APIs | Provides actual ORM behavior |
| Vendor-neutral | Hibernate-specific features |
π Hibernate implements JPA, but also offers extra features like:
Second-level cache
Hibernate Criteria API
Interceptors
An Entity is a persistent Java class mapped to a database table.
Annotated with @Entity
Must have a primary key
Must have a default constructor
Serializable (recommended)
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
@Id and @GeneratedValue?@Id → Marks the primary key
@GeneratedValue → Specifies how the primary key is generated
AUTO
IDENTITY
SEQUENCE
TABLE
@GeneratedValue(strategy = GenerationType.SEQUENCE)
A Persistence Context is a set of managed entity instances.
Managed by EntityManager
Ensures one object per database row
Tracks entity changes automatically
Transient – New object, not associated
Managed – Attached to persistence context
Detached – Exists but not managed
Removed – Marked for deletion
persist() and merge()| persist() | merge() |
|---|---|
| Used for new entities | Used for detached entities |
| Throws exception if entity exists | Updates existing entity |
| Returns void | Returns managed entity |
entityManager.persist(emp);
entityManager.merge(emp);
EntityManager is the core JPA interface for interacting with persistence context.
CRUD operations
Query execution
Transaction management
Common methods:
persist()
find()
remove()
merge()
createQuery()
@Transactional in JPA?@Transactional defines transaction boundaries.
Automatic commit/rollback
Cleaner code
Handles runtime exceptions
@Transactional
public void saveEmployee(Employee emp) {
entityManager.persist(emp);
}
find() and getReference()| find() | getReference() |
|---|---|
| Immediately hits DB | Returns proxy |
| Returns actual entity | Lazy-loaded |
| Null if not found | Exception on access |
JPQL (Java Persistence Query Language) is object-oriented query language.
SELECT e FROM Employee e WHERE e.salary > 50000
π Uses entity names and fields, not table/column names.
| JPQL | Native Query |
|---|---|
| Database independent | DB specific |
| Uses entity fields | Uses table columns |
| Slower for complex queries | Faster, optimized |
@Query(value = "SELECT * FROM employee", nativeQuery = true)
LAZY → Data loaded when accessed
EAGER → Data loaded immediately
@OneToMany(fetch = FetchType.LAZY)
Use LAZY by default
Avoid N+1 query issue
Occurs when:
One query loads parent entities
N queries load child entities
JOIN FETCH
Entity Graphs
Batch fetching
SELECT e FROM Employee e JOIN FETCH e.projects
@OneToOne
@OneToMany
@ManyToOne
@ManyToMany
@ManyToOne
@JoinColumn(name = "dept_id")
private Department department;
mappedBy and @JoinColumnmappedBy → Inverse side (no column created)
@JoinColumn → Owning side (creates FK)
Cascade propagates operations from parent to child.
PERSIST
MERGE
REMOVE
REFRESH
DETACH
ALL
@OneToMany(cascade = CascadeType.ALL)
Deletes child entity when removed from parent collection.
@OneToMany(orphanRemoval = true)
| First Level Cache | Second Level Cache |
|---|---|
| Default | Optional |
| EntityManager scoped | SessionFactory scoped |
| Always enabled | Requires config |
Uses @Version
No DB lock
Best for low contention
@Version
private int version;
DB-level lock
Used in high contention
JPA automatically detects entity changes and updates DB without explicit update query.
save() and saveAndFlush()save() → Persist later
saveAndFlush() → Immediately flush to DB
Flush synchronizes persistence context with database.
entityManager.flush();
@Embeddable and @Embedded?Used for value objects.
@Embeddable
class Address {}
@Embedded
private Address address;
Defines fetch plan dynamically to avoid N+1 issues.
How do you improve JPA performance in production?
Answer:
Use LAZY loading
Avoid unnecessary joins
Use pagination
Enable second-level cache
Use batch processing
Optimize queries
Avoid bi-directional relationships when not needed
CrudRepository → Basic CRUD
JpaRepository → Pagination, sorting, flush
Used for dynamic queries using Criteria API.
Complex joins
DB-specific functions
Performance-critical queries
@Transactional is missing?Partial updates
No rollback
Lazy loading exceptions
LazyInitializationException
EntityNotFoundException
OptimisticLockException
TransactionRequiredException
Optimistic locking
Pessimistic locking
Versioning
@Column(insertable=false, updatable=false)Used for read-only fields.
PageRequest.of(0, 10);
@OrderBy and @OrderColumn@OrderBy → Sorting
@OrderColumn → Maintains index
Prefer DTO projections
Avoid EAGER fetching
Use proper indexes
Handle transactions properly
Monitor SQL logs
Understand entity lifecycle
EntityManager and EntityManagerFactory?| EntityManager | EntityManagerFactory |
|---|---|
| Manages persistence context | Creates EntityManager instances |
| Lightweight | Heavyweight |
| Not thread-safe | Thread-safe |
| Per transaction/request | One per application |
Because it maintains:
Persistence context
Transaction state
Managed entity instances
Sharing it across threads can cause data inconsistency.
@Version and how does it work internally?@Version enables optimistic locking.
Entity loaded with version = 1
Update request checks version
If version mismatches → exception
@Version
private Long version;
Prevents lost updates without database locks.
Banking account profile update
Product catalog
Ticket booking
Inventory reservation
@Lock(LockModeType.PESSIMISTIC_WRITE)
Occurs when:
Lazy collection accessed outside transaction
Use JOIN FETCH
Open Session in View (not recommended)
DTO projection
Transactional service layer
DTO projection fetches only required columns.
SELECT new com.dto.EmployeeDTO(e.id, e.name)
FROM Employee e
Faster queries
Less memory usage
Better performance
JOIN, FETCH JOIN, and LEFT JOIN| JOIN | FETCH JOIN |
|---|---|
| Filters data | Fetches associations |
| Does not initialize collections | Initializes relations |
| Used in conditions | Avoids N+1 problem |
Criteria API builds type-safe dynamic queries.
Search screens
Dynamic filters
Complex conditions
@NamedQuery vs @Query?| @NamedQuery | @Query |
|---|---|
| Defined at entity level | Defined at repository |
| Precompiled | Runtime parsed |
| Better performance | More flexible |
flush() vs commit()?flush() → Syncs changes to DB
commit() → Finalizes transaction
Flush can happen multiple times before commit.
clear() in EntityManager?Removes all managed entities from persistence context.
entityManager.clear();
Used in batch processing.
Processing large data in chunks.
Use flush() and clear()
Disable second-level cache
Use batch size
hibernate.jdbc.batch_size=50
remove() and deleteById()remove() → Works on managed entity
deleteById() → Direct delete query
Instead of deleting records, mark them inactive.
@Where(clause = "is_deleted = false")
@DynamicUpdate?Updates only modified columns.
Reduces DB load
Improves performance
Caches entities across sessions.
Read-heavy applications
Rare updates
Do NOT use for frequently changing data.
@Where and @Filter| @Where | @Filter |
|---|---|
| Static condition | Dynamic condition |
| Always applied | Applied at runtime |
SINGLE_TABLE
JOINED
TABLE_PER_CLASS
Best practice: JOINED
@MappedSuperclass?Used for common fields like:
createdDate
updatedDate
No table created.
@Transient and transient?| @Transient | transient |
|---|---|
| JPA annotation | Java keyword |
| ORM ignored | Serialization ignored |
@ElementCollection?Used for value types without entity identity.
@ElementCollection
List<String> skills;
equals() and hashCode() in JPA entities?Should be based on:
Business key
Not auto-generated ID
Prevents issues in collections.
Callbacks for entity lifecycle events.
@PrePersist
@PreUpdate
@SQLDelete?Custom delete query (used for soft delete).
Automatically tracks:
CreatedBy
CreatedDate
ModifiedBy
ModifiedDate
Schema based
Database based
Discriminator based
@OrderBy and database ORDER BY@OrderBy → ORM-level sorting
SQL ORDER BY → DB-level sorting
Enable SQL logs
Analyze execution plan
Check indexes
Monitor N+1
Use query hints
@QueryHint?Provides optimization hints.
Bulk operations
Complex reporting
Highly DB-specific logic
Use JDBC / Native SQL instead.
How do you fix performance issues caused by bi-directional relationships?
Answer:
Make relationship uni-directional
Use DTO projections
Avoid EAGER fetching
Limit serialization (JSON infinite loop)
@JsonIgnore used for with JPA?Prevents infinite recursion during JSON serialization.
save() and persist()?save() → Spring Data JPA
persist() → JPA EntityManager
@Immutable?Marks entity as read-only.
Entity scanning
Mapping validation
Schema generation (ddl-auto)
Use:
Flyway
Liquibase
Never rely on ddl-auto in production.
@PrePersist
@PostPersist
@PreUpdate
@PostUpdate
@PreRemove
@PostRemove
findAll() and pagination?findAll() loads everything
Pagination loads limited data
FetchType.EAGER in production?Performance issues
Unnecessary joins
Memory overhead
Avoid it.
DTO projections
Lazy loading
Proper indexing
Batch processing
Caching strategy
Monitoring