Part 5 – JPA and Hibernate Fundamentals


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:

JavaDatabase
ClassTable
ObjectRow
FieldColumn
RelationshipForeign Key

Example:

Employee.java
        ↓
EMPLOYEE table

JPA vs Hibernate

TechnologyDescription
JPASpecification
HibernateImplementation
EclipseLinkImplementation
Spring Data JPARepository 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

AttributePurpose
nameColumn name
nullableNULL allowed
lengthVARCHAR size
uniqueUnique constraint
precisionNumbers
scaleDecimal 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

@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

AnnotationTrigger
@PrePersistBefore insert
@PostPersistAfter insert
@PreUpdateBefore update
@PostUpdateAfter update
@PreRemoveBefore 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

ModePurpose
noneNo changes
validateValidate schema
updateUpdate schema
createCreate schema
create-dropDrop 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

Leave a Reply

Your email address will not be published. Required fields are marked *