Introduction
Most modern Java applications do not directly use JDBC. Instead, they use an Object Relational Mapping (ORM) framework such as Hibernate through the Java Persistence API (JPA).
JPA solves one of the biggest challenges in application development:
How do we map Java objects to relational database tables?
Without JPA:
- Developers write SQL.
- Developers map ResultSets manually.
- Developers manage relationships manually.
With JPA:
- Objects become entities.
- Relationships become annotations.
- SQL generation becomes automatic.
- Persistence becomes easier.
This article covers:
✅ ORM concepts
✅ Entity mapping
✅ Primary key generation
✅ Column mapping
✅ Java datatype mapping
✅ Validation
✅ Auditing
✅ Lifecycle events
✅ Spring Data JPA
What is ORM?
ORM stands for:
Object Relational Mapping
It maps:
| Java | Database |
|---|---|
| Class | Table |
| Object | Row |
| Field | Column |
| Relationship | Foreign Key |
Example:
Employee.java
↓
EMPLOYEE table
JPA vs Hibernate
| Technology | Description |
|---|---|
| JPA | Specification |
| Hibernate | Implementation |
| EclipseLink | Implementation |
| Spring Data JPA | Repository abstraction |
Think of JPA as the interface and Hibernate as the implementation.
Maven Dependencies
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-jpa
</artifactId>
</dependency>
<dependency>
<groupId>
com.oracle.database.jdbc
</groupId>
<artifactId>ojdbc11</artifactId>
</dependency>
Basic Entity
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
Marks a Java class as persistent.
@Entity
public class Employee {
}
Without @Entity:
- Hibernate ignores the class.
@Table
Maps to a table.
@Table(name = "EMPLOYEE")
Optional:
@Entity
public class Employee {
}
Table defaults to:
EMPLOYEE
@Id
Defines the primary key.
@Id
private Long id;
Every entity requires an identifier.
Primary Key Generation
JPA supports multiple strategies.
AUTO
@GeneratedValue(
strategy = GenerationType.AUTO)
Provider decides.
IDENTITY
@GeneratedValue(
strategy = GenerationType.IDENTITY)
Database generates values.
SEQUENCE
Recommended for Oracle.
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "emp_seq")
Sequence Example
@SequenceGenerator(
name = "emp_seq",
sequenceName = "EMP_SEQ",
allocationSize = 50)
Why allocationSize Matters
Bad:
allocationSize = 1
Every insert:
Application
↓
Sequence call
↓
Insert
Good:
allocationSize = 50
Hibernate caches IDs.
Benefits:
- Fewer database calls.
- Better performance.
UUID Primary Keys
@Id
private UUID id;
Database:
EMP_ID RAW(16)
Advantages:
- Distributed systems.
- Global uniqueness.
Disadvantages:
- Larger indexes.
- Random inserts.
@Column
@Column(
name = "FIRST_NAME",
length = 100,
nullable = false)
private String firstName;
Important Attributes
| Attribute | Purpose |
|---|---|
| name | Column name |
| nullable | NULL allowed |
| length | VARCHAR size |
| unique | Unique constraint |
| precision | Numbers |
| scale | Decimal places |
Numeric Mapping
@Column(
precision = 12,
scale = 2)
private BigDecimal salary;
Database:
SALARY NUMBER(12,2)
Date Mapping
LocalDate
private LocalDate joiningDate;
LocalDateTime
private LocalDateTime createdDate;
Instant
private Instant eventTime;
Recommended for:
- Audit timestamps.
- Events.
- Messaging.
Large Objects
@Lob
private String description;
Maps to:
CLOB
@Lob
private byte[] document;
Maps to:
BLOB
Enumerations
public enum Status {
ACTIVE,
INACTIVE
}
Entity:
@Enumerated(EnumType.STRING)
private Status status;
Database:
ACTIVE
Avoid:
EnumType.ORDINAL
Because enum order changes can corrupt data.
Transient Fields
@Transient
private Integer age;
Not stored in the database.
Validation
Not Null
@NotNull
private String name;
Size
@Size(max = 100)
private String firstName;
@Email
private String email;
Positive
@Positive
private BigDecimal salary;
Auditing Fields
Every entity should contain:
private LocalDateTime createdDate;
private String createdBy;
private LocalDateTime updatedDate;
private String updatedBy;
Entity Listener
@PrePersist
public void beforeInsert() {
createdDate =
LocalDateTime.now();
}
Lifecycle Methods
| Annotation | Trigger |
|---|---|
| @PrePersist | Before insert |
| @PostPersist | After insert |
| @PreUpdate | Before update |
| @PostUpdate | After update |
| @PreRemove | Before delete |
Optimistic Locking
@Version
private Integer version;
Benefits:
- Prevents lost updates.
- Supports concurrent users.
Spring Data Repository
@Repository
public interface EmployeeRepository
extends JpaRepository<Employee, Long> {
}
Provides:
- save()
- findById()
- delete()
- findAll()
Custom Queries
List<Employee>
findByStatus(String status);
Spring generates SQL automatically.
JPQL
@Query("""
select e
from Employee e
where e.salary > :salary
""")
Works with entities.
Native SQL
@Query(
value =
"select * from employee",
nativeQuery = true)
Use when:
- Oracle functions.
- Performance tuning.
- Complex SQL.
Hibernate Configuration
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.format_sql=true
DDL Auto Modes
| Mode | Purpose |
|---|---|
| none | No changes |
| validate | Validate schema |
| update | Update schema |
| create | Create schema |
| create-drop | Drop on shutdown |
Production:
validate
Entity Example
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "emp_seq")
private Long id;
@Column(length = 100)
private String name;
@Column(
precision = 12,
scale = 2)
private BigDecimal salary;
private LocalDate joiningDate;
@Version
private Integer version;
}
Common Mistakes
Using EAGER Everywhere
@OneToMany(
fetch = FetchType.EAGER)
Bad.
Using Double
private double salary;
Bad.
Using Enum ORDINAL
EnumType.ORDINAL
Bad.
Missing Version Column
No optimistic locking.
Using update in Production
ddl-auto=update
Avoid.
Best Practices
✅ Use sequences in Oracle.
✅ Use BigDecimal for money.
✅ Use LocalDate for dates.
✅ Use Instant for timestamps.
✅ Use EnumType.STRING.
✅ Add version columns.
✅ Add audit columns.
✅ Use validation annotations.
✅ Prefer validate mode.
Interview Questions
Difference between JPA and Hibernate?
JPA is a specification.
Hibernate is an implementation.
Why use SEQUENCE in Oracle?
Best performance.
Why avoid ORDINAL?
Enum order changes break data.
Why use @Version?
Optimistic locking.
Difference between LocalDate and LocalDateTime?
LocalDate contains only date.
LocalDateTime contains date and time.
Summary
This article covered:
✅ JPA fundamentals
✅ Entity mapping
✅ Primary keys
✅ Sequences
✅ UUIDs
✅ Validation
✅ Auditing
✅ Versioning
✅ Spring Data JPA
Next Article
Part 6 – Relationships and Joins
Topics:
- One-to-One
- One-to-Many
- Many-to-One
- Many-to-Many
- Join tables
- Cascade types
- Orphan removal
- Bidirectional relationships
- Join fetch
- SQL generated by Hibernate