Overview
A specification: A standard set of rules and annotations (
@Entity,@Id, etc.) for how ORM should work in Java.
- Hibernate: The most famous and widely used implementation of the JPA specification. When you use JPA, you are most likely using the Hibernate engine underneath.
- It’s NOT a TOOL, but a SPECIFICATION
- Spring Data Access Technologies
- Spring Data JPA gives you a higher abstraction
- Requires a solid understanding of concepts like the Persistence Context, caching, and the N+1 problem.
- standard specification
- it’s defined as a set of Java interfaces, which means separate implementations exist which bring this JPA standard to life
- learning JPA = learning about one of the specific implementations of the JPA standard
- historically the
javax.persistencepackage, nowjakarta.persistence - Spring AOP and Transactions: JpaTransactionManager - Transaction Manager
| Feature | Description |
|---|---|
| Improved Productivity | Can handle CRUD operations without directly writing SQL. |
| Easy Maintenance | Code is written based on objects; readability is improved by separating it from SQL. |
| DBMS Independence | Minimizes dependency on specific SQL dialects, reducing the impact of database changes. |
| ORM Functionality | Provides automatic mapping between Java objects and database tables. |
Hibernate
- JPA = Standard interface for ORM in Java
- Hibernate ORM
- JPA implementation (aka provider), an ORM framework
- Follows the JPA specification and also provides additional, advanced features
- Most popular & representative. Other implementations include EclipseLink, and DataNucleus, etc
Diagram: Repository layer

Application → JPA Interface → Hibernate → JDBC → DB
- Operations like saving and retrieving data are processed through JPA and then handled by its implementation, Hibernate ORM.
- Internally, Hibernate ORM uses the JDBC API to access the database.
- Focus: Learning how to access the database using the API provided by JPA, which sits at the top of the data access layer.
How it works + Key Components
| Term | Description |
|---|---|
| Entity | A Java class that is mapped to a database table. |
| EntityManager | The primary object responsible for managing Entities (saving, retrieving, deleting, etc.). |
| Persistence Context | A space where entities are managed; acts as a 1st-level cache. |
| Transaction | All data modifications must be performed within a transaction. |
Entity
@Entity+@Idannotation needed@Id= Primary Key@GeneratedValue= PK 자동 생성 전략
- Each entity instance is 1 row of the db table!
- Read more in Entity Design
@Entity
@Table(name = "members")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}EntityManager
- It is the core interface of JPA.
- It manages the Entity lifecycle, handles CRUD operations, and executes JPQL (Java Persistence Query Language) queries.
EntityManager em = emf.createEntityManager();- Main functions
em.persist()- Save a new entity (INSERT)em.find()- Find by Primary Key (SELECT)em.remove()- Delete an entity (DELETE) from the persistence contextem.flush()- Saves the persistence context’s changes to the DBem.merge()- Merge a detached entity (UPDATE)
Persistence Context
JPA -> Persistence Context -> DB
- Persistence = make something last longer w/o it disappearing
- The concept
- ORM is a technology that saves information from entity objects into database tables by mapping those objects to the tables.
- In JPA, information from entity objects is stored in a place called the Persistence Context to make it last within the application. This stored entity information is then used to save, modify, retrieve, and delete data in the database tables.
- diagram

Example
Notice we’re writing the
EntityTransaction manually
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); // start transaction
Member member = new Member("홍길동", 29);
em.persist(member); // (1) This does NOT execute the INSERT yet
Member foundMember = em.find(Member.class, 1L); // (2) Find example (utilizing the 1st-level cache)
tx.commit(); // (3) The INSERT is executed when the transaction commits
- Steps
- Create an Entity → Enter the “persistent state” via
persist()(This is not yet saved to the DB). - When retrieving data (
find()), the 1st-level cache (Persistence Context) is searched first. - The actual SQL is executed when the transaction commits → new member is added to the actual db (The change is reflected in the DB)
- Create an Entity → Enter the “persistent state” via
tx.commit- Contains
em.flush(): TheEntityManagerlooks at the commands (persistin this case) and figures out what SQL needs to be sent to the db + generates theINSERTstatement and sends to DB - contains all other necessary stuff
- Persistence Context (the 1st-level cache) is CLEARED
- Contains
- Benefits
- Performance: Imagine you
persist10 different members. Instead of making 10 separate trips to the database (which is slow), theEntityManagercan collect all 10 members and often optimize them into a single, efficient batch operation atcommittime - 1st-Level Cache: The Persistence Context acts as a cache for the duration of a single transaction.
- If an entity is already in the Persistence Context (like a cache)→
em.find()returns the cached object, no DB query - Our example: After
persist(member), callingfind(Member.class, 1L)returns the same object directly from the cache - ✅ Improves performance by avoiding unnecessary DB hits
- If an entity is already in the Persistence Context (like a cache)→
- Performance: Imagine you
- A more comprehensive example: 코드잇 노트
Example 2
private void example() {
tx.begin();
em.persist(new Member("hgd1@gmail.com")); // (1)
tx.commit(); //(2)
tx.begin();
Member member = em.find(Member.class, 1L); // (3)
em.remove(member); // (4)
tx.commit(); // (5)
}- The new
Memberobject is placed into the cache INSERTstatement is sent to the database, persistence context is cleared (cache empty)- The
EntityManagerlooks forMemberwith ID1in its cache. The cache is empty. Therefore, it has no choice but to generate aSELECTquery and fetch the data from the database- Once found, the object is placed in the cache
em.remove(): TheMemberis marked for deletiontx.commit(): ADELETEstatement is sent to the database
@Transactional
Manual method
EntityTransaction tx = em.getTransaction();
- When using manual transaction management with
EntityTransaction, the persistence context is tied to the transaction lifecycle. Eachcommit()orrollback()will clear it. - See examples above
@Transactional
@Transactional
private void example() {
// Spring starts the transaction and creates a Persistence Context.
// (1) The new Member is placed in the Persistence Context.
// NO SQL has been sent yet.
em.persist(new Member("hgd1@gmail.com"));
// (2) em.find() looks in the cache, finds the Member, and returns it.
// Still NO database interaction.
Member member = em.find(Member.class, 1L);
// (3) The Member is marked for removal in the Persistence Context.
// Still NO SQL has been sent.
em.remove(member);
} // (4) Method ends. NOW, Spring tells JPA to:
// a. Flush: JPA looks at the context. It sees a new entity that was also removed,
// so it might optimize by sending NO SQL AT ALL. If it weren't removed,
// the INSERT and DELETE would be sent here.
// b. Commit: The database transaction is committed.
// c. Cleanup: The Persistence Context is cleared.Manual vs. @Transactional
| Aspect | Manual Transaction | @Transactional |
|---|---|---|
| Transaction Scope | tx.begin() → tx.commit() | Entire method is one transaction |
| Persistence Context | Cleared after each tx.commit() | Lives through the whole method, cleared at end |
DB Interaction (e.g. find) | Hits DB after tx.commit() | Returns from Persistence Context, no query |
| SQL Execution | Separate INSERT, DELETE txs | Combined into one transaction → more efficient |
Tip
- JPA improves code maintainability by separating business logic from DB queries.
- It pairs well with object-oriented development approaches like Domain-Driven Design (DDD).
- For complex dynamic queries, using a library like QueryDSL alongside JPA is recommended.
- It is crucial to understand and properly use the Persistence Context within the scope of a transaction.