Mapping Entities with Hibernate: @Entity, @Table, and @Id Explained

Illustration for Mapping Entities with Hibernate: @Entity, @Table, and @Id Explained
By Last updated:

When working with Hibernate, the first step in interacting with the database is mapping Java classes to relational database tables. Hibernate achieves this through annotations like @Entity, @Table, and @Id. These annotations form the foundation of Object-Relational Mapping (ORM) in Hibernate.

In this tutorial, we’ll explore how to use these annotations effectively, dive into real-world examples, and build CRUD operations. By the end, you’ll understand how entity mapping simplifies database operations, improves maintainability, and integrates seamlessly with frameworks like Spring Boot.


What is an Entity in Hibernate?

An Entity in Hibernate represents a table in a database. Each entity instance corresponds to a row in that table.

  • @Entity → Marks the class as a persistent entity.
  • @Table → Maps the entity to a specific table (optional if class name matches).
  • @Id → Defines the primary key.

Think of it this way:

  • Entity Class = Table
  • Entity Instance = Table Row

Example: Basic Entity Mapping

import jakarta.persistence.*;

@Entity
@Table(name = "students")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "student_name", nullable = false, length = 100)
    private String name;

    @Column(name = "age")
    private int age;

    public Student() {}
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Getters and setters
}

Explanation

  • @Entity: Marks Student as an entity class.
  • @Table(name = "students"): Maps class to table students.
  • @Id: Marks id as primary key.
  • @GeneratedValue: Defines how IDs are generated (AUTO, IDENTITY, SEQUENCE).
  • @Column: Maps class fields to table columns.

Relationships in Entity Mapping

Hibernate makes it easy to define relationships between entities.

One-to-Many Example

@Entity
@Table(name = "courses")
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "course", cascade = CascadeType.ALL)
    private List<Student> students = new ArrayList<>();
}

Many-to-One Example

@ManyToOne
@JoinColumn(name = "course_id")
private Course course;

Hibernate Configuration (hibernate.cfg.xml)

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/testdb</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="hibernate.show_sql">true</property>
    <mapping class="com.example.Student"/>
    <mapping class="com.example.Course"/>
  </session-factory>
</hibernate-configuration>

CRUD Operations with Entities

Create

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

Student student = new Student("Alice", 22);
session.persist(student);

tx.commit();
session.close();

Read

Session session = HibernateUtil.getSessionFactory().openSession();
Student student = session.get(Student.class, 1L);
System.out.println(student.getName());
session.close();

Update

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

Student student = session.get(Student.class, 1L);
student.setName("Updated Name");
session.update(student);

tx.commit();
session.close();

Delete

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

Student student = session.get(Student.class, 1L);
session.remove(student);

tx.commit();
session.close();

Querying with Entities

HQL Example

List<Student> students = session.createQuery("FROM Student WHERE age > :age", Student.class)
        .setParameter("age", 20)
        .list();

Criteria API Example

CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
cq.select(root).where(cb.greaterThan(root.get("age"), 20));
List<Student> students = session.createQuery(cq).getResultList();

Caching and Performance Considerations

  • Lazy Loading (default) → Fetch associations only when accessed.
  • Eager Loading → Fetch associations immediately.
  • First-Level Cache → Session-specific cache.
  • Second-Level Cache → Application-wide, enabled via SessionFactory.

Analogy:

  • Lazy loading = ordering food when you’re hungry.
  • Caching = reusing already fetched data instead of going back to the database.

Real-World Integration with Spring Boot

Spring Boot simplifies Hibernate setup using Spring Data JPA:

spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

Repository Example:

public interface StudentRepository extends JpaRepository<Student, Long> {}

Common Pitfalls

  • Forgetting @Id → Hibernate won’t recognize the entity.
  • Using eager fetching everywhere → performance issues.
  • Incorrect cascade setup → can lead to unintended deletes.

Best Practices

  • Always define a primary key with @Id.
  • Use lazy fetching by default.
  • Use DTOs for API responses.
  • Keep entities lean and avoid business logic inside them.

📌 Hibernate Version Notes

Hibernate 5.x

  • Relies on javax.persistence.
  • Legacy APIs for configuration and criteria.

Hibernate 6.x

  • Migrated to jakarta.persistence.
  • Enhanced query API and SQL support.
  • Better bootstrap and metadata handling.

Conclusion and Key Takeaways

  • @Entity, @Table, and @Id form the backbone of Hibernate ORM.
  • Entities map Java classes to database tables, enabling seamless CRUD operations.
  • Relationships like One-to-Many and Many-to-One are handled via annotations.
  • Hibernate integrates seamlessly with Spring Boot and JPA.
  • Always follow best practices for fetching and cascading to avoid pitfalls.

FAQ: Expert Hibernate Questions

  1. What’s the difference between Hibernate and JPA?
    JPA is a specification, while Hibernate is a popular implementation.

  2. How does Hibernate caching improve performance?
    By reducing database trips using first and second-level caches.

  3. What are the drawbacks of eager fetching?
    Loads unnecessary data upfront, slowing performance.

  4. How do I solve the N+1 select problem?
    Use JOIN FETCH, batch fetching, or entity graphs.

  5. Can I use Hibernate without Spring?
    Yes, Hibernate can run standalone.

  6. What’s the best inheritance mapping strategy?
    JOINED for normalization, SINGLE_TABLE for speed.

  7. How does Hibernate handle composite keys?
    With @EmbeddedId or @IdClass.

  8. How is Hibernate 6 different from Hibernate 5?
    Hibernate 6 uses jakarta.persistence, with enhanced SQL APIs.

  9. Is Hibernate suitable for microservices?
    Yes, but prefer DTOs and stateless design.

  10. When should I not use Hibernate?
    Avoid in raw SQL-heavy analytics or batch processing apps.