JPA vs Hibernate
BeginnerJPA is the Java specification (API + annotations); Hibernate is the most popular implementation. You code against JPA interfaces for portability but benefit from Hibernate-specific features.
Overview
JPA (Jakarta Persistence API, formerly Java Persistence API) is a specification defined in JSR 338 that standardises ORM concepts: @Entity, @Table, @OneToMany, EntityManager, JPQL, Criteria API, and the persistence lifecycle. Hibernate is the most widely used JPA implementation (also ships alternatives: EclipseLink, DataNucleus). By coding to JPA interfaces you gain theoretical portability, but in practice projects rely on Hibernate-specific features (HQL extensions, @NaturalId, @BatchSize, Statistics, etc.) that tie them to Hibernate. Spring Data JPA sits on top, adding repository abstractions and query derivation.
JPA Specification vs Hibernate Implementation
JPA defines the standard API. Hibernate implements it and adds extensions. When you code to JPA you use EntityManager, @Entity, JPQL etc. — these work on any provider. Hibernate extras (@Filter, @NaturalId, HQL extensions) only work on Hibernate.
// JPA-standard — works on any provider
import jakarta.persistence.*;
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
private Category category;
}
// JPA standard EntityManager
@Repository
public class ProductJpaRepository {
@PersistenceContext
private EntityManager em;
public Optional<Product> findById(Long id) {
return Optional.ofNullable(em.find(Product.class, id));
}
}
// Hibernate-specific — tied to Hibernate
import org.hibernate.annotations.NaturalId;
import org.hibernate.annotations.BatchSize;
@Entity
public class Product {
@NaturalId // Hibernate-specific: cache by natural key
private String sku;
@BatchSize(size = 25) // Hibernate-specific: IN-clause batch loading
@OneToMany(mappedBy = "product")
private List<Review> reviews;
}Spring Data JPA Layer
Spring Data JPA sits on top of JPA and Hibernate. JpaRepository<T,ID> provides CRUD and pagination. Query derivation generates JPQL from method names. @Query adds custom JPQL or native SQL. Under the hood it all delegates to Hibernate's EntityManager.
// Layer stack:
// Spring Data JPA (JpaRepository, query derivation)
// ↓
// JPA (EntityManager, JPQL, Criteria API)
// ↓
// Hibernate (SQL generation, caching, dirty checking, schema validation)
// ↓
// JDBC (connection pool — HikariCP)
// ↓
// Database (MySQL, PostgreSQL, etc.)
// Spring Data JPA repository — uses JPA under the hood
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
// Query derivation → SELECT * FROM products WHERE name = ? AND active = ?
List<Product> findByNameAndActiveTrue(String name);
// Custom JPQL
@Query("SELECT p FROM Product p WHERE p.price < :max ORDER BY p.price")
List<Product> findCheaperThan(@Param("max") BigDecimal maxPrice);
}
// Auto-configured in Spring Boot:
// spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
// spring.jpa.show-sql=true
// spring.jpa.properties.hibernate.format_sql=trueWhen to Use JPA vs Hibernate Specifics
Start with JPA annotations and Spring Data repositories. Reach for Hibernate-specific features only when JPA standard is insufficient — e.g. @Filter for soft deletes, @NaturalId for business key lookups, or second-level cache configuration.
// ─── When JPA standard is enough ────────────────────────────────
// CRUD via JpaRepository (Spring Data)
// JPQL / @Query for custom queries
// Criteria API for dynamic queries
// @OneToMany, @ManyToOne, @ManyToMany relationships
// @PrePersist, @PostUpdate lifecycle callbacks
// ─── Reach for Hibernate-specific when ───────────────────────────
// Soft deletes:
@Entity
@FilterDef(name = "activeFilter", defaultCondition = "deleted = false")
@Filter(name = "activeFilter")
public class Product { ... }
// Second-level cache:
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Category { ... }
// Pessimistic locking with hints:
em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE,
Map.of("jakarta.persistence.lock.timeout", 2000L));
// StatelessSession for bulk processing (bypasses dirty checking, L1 cache)
try (StatelessSession session = sf.openStatelessSession()) {
session.doWork(conn -> {
// raw JDBC operations via Hibernate session
});
}Key Points to Remember
- 1JPA is the specification (annotations, EntityManager, JPQL); Hibernate is the implementation.
- 2Code to JPA interfaces for portability; use Hibernate-specific features only when needed.
- 3Spring Data JPA sits above JPA — JpaRepository generates queries using Hibernate under the hood.
- 4@Entity, @Id, @ManyToOne, @Query — all JPA standard; @NaturalId, @Filter, @Cache — Hibernate-specific.
- 5The full stack: Spring Data JPA → JPA (EntityManager) → Hibernate → HikariCP → DB.
- 6spring.jpa.show-sql=true and format_sql=true are invaluable for debugging generated SQL.
Interview Questions
Sign in to ask AriaWhat is the difference between JPA and Hibernate?
Why would you code to JPA interfaces rather than Hibernate directly?
Where does Spring Data JPA fit in the JPA/Hibernate stack?
What Hibernate-specific annotation would you use for a soft-delete filter?
What is the difference between EntityManager and StatelessSession in Hibernate?
Ask Aria about JPA vs Hibernate
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.