Junior 3 min · March 09, 2026

Hibernate Mapping: Missing mappedBy Causes Duplicate FK

Hibernate generates duplicate UPDATEs for a foreign key column when @OneToMany lacks mappedBy.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • Hibernate Entity Mapping defines how Java objects map to database tables using JPA annotations
  • Core components: @Entity, @Table, @Column, @Id, @GeneratedValue define structure
  • Relationship mappings: @OneToMany, @ManyToOne, @JoinColumn define foreign key relationships
  • Performance insight: Lazy fetching avoids the N+1 query problem; always prefer FetchType.LAZY by default
  • Production insight: Omitting mappedBy or using wrong cascade type can cause redundant queries or constraint violations
  • Biggest mistake: Relying on default naming strategies leads to inconsistent schemas across environments
Plain-English First

Think of Hibernate Entity Mapping as a universal translator. On one side, you have your Java code (which thinks in terms of 'Objects' and 'Collections'), and on the other, you have a Relational Database (which thinks in terms of 'Tables' and 'Foreign Keys'). Entity mapping is the set of rules you write to tell Hibernate exactly which Java field matches which database column, so they can talk to each other without you writing endless SQL manually.

Hibernate Entity Mapping is a fundamental concept in Java development and the backbone of the Java Persistence API (JPA). It allows developers to define the relationship between the object-oriented domain model and the relational database schema.

In this guide, we'll break down exactly what Hibernate Entity Mapping is, why it was designed to bridge the 'impedance mismatch' between objects and tables, and how to use it correctly in real projects. We will explore how annotations transform simple POJOs into managed entities that Hibernate can persist, query, and optimize.

By the end, you'll have both the conceptual understanding and practical code examples to use Hibernate Entity Mapping with confidence in your 'io.thecodeforge' production microservices.

What Is Hibernate Entity Mapping and Why Does It Exist?

Hibernate Entity Mapping exists to solve the problem of data persistence in object-oriented programming. In a standard SQL approach, you spend significant time mapping ResultSet rows to Java objects. Hibernate automates this via annotations like @Entity, @Table, and @Column. This abstraction allows developers to focus on business logic rather than database plumbing.

By defining these mappings, Hibernate can automatically generate the necessary SQL (DDL and DML) to synchronize your application state with the database. It handles the type conversion between Java types (like LocalDateTime or Enum) and SQL types (like TIMESTAMP or VARCHAR), ensuring that your data remains consistent across different database dialects.

UserAccount.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package io.thecodeforge.entities;

import jakarta.persistence.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.time.LocalDateTime;

/**
 * io.thecodeforge: Production-grade Entity Mapping
 * Utilizing Hibernate-specific enhancements for audit logging.
 */
@Entity
@Table(name = "forge_users", indexes = {
    @Index(name = "idx_username", columnList = "username"),
    @Index(name = "idx_email", columnList = "email_address")
})
public class UserAccount {

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

    @Column(name = "username", nullable = false, unique = true, length = 50)
    private String username;

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

    @Enumerated(EnumType.STRING)
    @Column(name = "account_status", nullable = false)
    private AccountStatus status = AccountStatus.ACTIVE;

    @CreationTimestamp
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @UpdateTimestamp
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    public enum AccountStatus {
        ACTIVE, SUSPENDED, DELETED
    }

    // Standard Getters/Setters
}
Output
Hibernate generates: CREATE TABLE forge_users (id BIGINT NOT NULL AUTO_INCREMENT, username VARCHAR(50) UNIQUE, email_address VARCHAR(100), account_status VARCHAR(255), created_at TIMESTAMP, updated_at TIMESTAMP, PRIMARY KEY (id))
Key Insight:
The most important thing to understand about Hibernate Mapping is that your entity acts as a blueprint. Always ask 'How should this object look in a table?' before writing your annotations.
Production Insight
Never rely on Hibernate's auto-generated table names without explicit @Table annotation.
Different database environments (e.g., case sensitivity) can break your schema.
Rule: always define @Table, @Column, and naming strategy explicitly in production.
Key Takeaway
Hibernate entity mapping bridges OOP and SQL.
Use explicit annotations for schema portability.
Your entity is a blueprint — design it with the table in mind.

Column Mapping and Type Conversion Deep Dive

Beyond basic @Column, you need to control length, nullability, uniqueness, and precision. For monetary values, use @Column(precision = 19, scale = 2). For dates, prefer java.time.LocalDate or LocalDateTime with @CreationTimestamp and @UpdateTimestamp for automatic audit fields.

Type mapping between Java enums and database columns can be done via @Enumerated(EnumType.STRING) or (ORDINAL). STRING is safer for production because ordinal values shift when enums are reordered. For custom types (JSON, arrays), implement a Hibernate UserType or use the @JdbcTypeCode annotation (Hibernate 6+).

ProductEntity.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package io.thecodeforge.entities;

import jakarta.persistence.*;
import java.math.BigDecimal;

@Entity
@Table(name = "forge_products")
public class Product {

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

    @Column(name = "product_name", nullable = false, length = 150)
    private String name;

    @Column(name = "price", nullable = false, precision = 19, scale = 2)
    private BigDecimal price;

    @Enumerated(EnumType.STRING)
    @Column(name = "category", nullable = false, length = 50)
    private Category category;

    @Lob
    @Column(name = "description")
    private String description;  // Maps to TEXT for large strings

    public enum Category {
        ELECTRONICS, CLOTHING, BOOKS
    }

    // Getters/Setters
}
Output
Hibernate generates: CREATE TABLE forge_products (id BIGINT NOT NULL AUTO_INCREMENT, product_name VARCHAR(150) NOT NULL, price DECIMAL(19,2) NOT NULL, category VARCHAR(50) NOT NULL, description TEXT, PRIMARY KEY (id))
Watch Out:
Avoid @Lob for strings unless you truly need unlimited length. It forces a TEXT column which cannot be efficiently indexed in most databases. Use @Column(length = N) with a reasonable max.
Production Insight
Decimal precision matters when currencies are involved — wrong scale = rounding errors.
Always test DDL generation on a staging environment before production.
Rule: use @Column(precision, scale) for monetary fields.
Key Takeaway
Explicit column definitions prevent schema drift.
Use @Enumerated(EnumType.STRING) for enums.
For audit timestamps, use @CreationTimestamp and @UpdateTimestamp.

Relationship Mapping: One-to-Many, Many-to-One, Many-to-Many

In relational databases, relationships are expressed through foreign keys. Hibernate maps these via annotations. The most common pattern is @OneToMany (collection on parent) with @ManyToOne (reference on child). The side with the @ManyToOne is always the owning side and contains @JoinColumn(name = "fk_column"). The @OneToMany side uses mappedBy to point back to the field name on the owning side.

For @ManyToMany, avoid using default join tables without extra columns. If you ever need to store metadata (like created_date), create a separate entity with two @ManyToOne references and convert to two @OneToMany relationships. Always prefer unidirectional mappings when possible — they're simpler and easier to optimize.

OrderEntity.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package io.thecodeforge.entities;

import jakarta.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "forge_orders")
public class Order {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_id", nullable = false)
    private Customer customer;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    private List<OrderItem> items = new ArrayList<>();

    @Column(name = "total", precision = 19, scale = 2)
    private BigDecimal total;

    @CreationTimestamp
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    public void addItem(OrderItem item) {
        items.add(item);
        item.setOrder(this);
    }

    // Getters/Setters
}

@Entity
@Table(name = "forge_order_items")
public class OrderItem {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id", nullable = false)
    private Order order;

    @Column(name = "product_name", nullable = false, length = 150)
    private String productName;

    @Column(name = "quantity", nullable = false)
    private Integer quantity;

    @Column(name = "unit_price", precision = 10, scale = 2)
    private BigDecimal unitPrice;

    // Getters/Setters
}
Output
Hibernate generates: CREATE TABLE forge_orders (customer_id BIGINT NOT NULL, ...); CREATE TABLE forge_order_items (order_id BIGINT NOT NULL REFERENCES forge_orders(id));
Owning vs Inverse Side
  • Owning side: contains @JoinColumn and manages the foreign key.
  • Inverse side: uses mappedBy to refer to the owning side's field name.
  • Only the owning side's changes are persisted to the database.
  • Both sides should be kept in sync using helper methods like addItem().
Production Insight
Omitting mappedBy creates duplicate foreign key columns — Hibernate treats both as owners.
Missing cascade leads to 'detached entity passed to persist' errors.
Rule: always define the owning side correctly and sync both sides programmatically.
Key Takeaway
The owning side controls the foreign key.
Always use mappedBy on the @OneToMany side.
Helper methods prevent state inconsistency.
Choosing Bidirectional vs Unidirectional Relationship
IfYou only need to navigate from parent to child in queries
UseUse unidirectional @OneToMany without mappedBy, but be aware it creates a join table by default.
IfYou need to navigate from child to parent as well
UseUse bidirectional with @ManyToOne as owning side and @OneToMany(mappedBy=...) on the inverse.
IfYou need to store additional columns on the relationship
UseConvert @ManyToMany or unidirectional @OneToMany into a separate entity with two @ManyToOne sides.

Fetching Strategies: LAZY vs EAGER and the N+1 Problem

The fetch type determines when related entities are loaded. EAGER loads them immediately, often causing large SQL joins or multiple selects. LAZY defers loading until first access, but if accessed inside a closed transaction, you get a LazyInitializationException.

The infamous N+1 select problem happens when you load N entities and each fires an extra query for its relationship. This is typical when you iterate over a list and access a LAZY association without proper batch fetching. Solutions: use JOIN FETCH in JPQL, @EntityGraph on repository methods, or Hibernate's @BatchSize.

RepositoryQuery.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package io.thecodeforge.repositories;

import io.thecodeforge.entities.Order;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;

public interface OrderRepository extends JpaRepository<Order, Long> {

    // Solution 1: JOIN FETCH in JPQL
    @Query("SELECT o FROM Order o JOIN FETCH o.items")
    List<Order> findAllWithItemsUsingJoinFetch();

    // Solution 2: EntityGraph (more declarative)
    @EntityGraph(attributePaths = {"items"})
    @Query("SELECT o FROM Order o")
    List<Order> findAllWithItemsUsingEntityGraph();

    // Solution 3: Batch size (Hibernate-specific)
    // In application.properties: spring.jpa.properties.hibernate.default_batch_fetch_size=10
    @Query("SELECT o FROM Order o")
    List<Order> findAllWithBatchSize();
}
Output
JOIN FETCH generates a single SQL query with an INNER JOIN instead of N+1 selects. EntityGraph produces the same result with annotation-based configuration.
Production Snare:
Never use FetchType.EAGER on collection mappings (@OneToMany, @ManyToMany). It forces Hibernate to load everything upfront, leading to massive memory consumption and performance crashes. Always default to LAZY and tune fetch strategies at the query level.
Production Insight
An EAGER @OneToMany loads the entire collection for every parent — even when you only need basic fields.
This is a common cause of OutOfMemoryError in production.
Rule: use LAZY by default and override with JOIN FETCH for specific use cases.
Key Takeaway
LAZY loading saves memory.
JOIN FETCH solves N+1 at query time.
Default batch fetch size reduces round trips.

Inheritance Mapping Strategies: Choosing the Right Model

JPA supports three class-table inheritance strategies. SINGLE_TABLE uses a single table with a discriminator column — simple but wastes nullable columns. JOINED uses separate tables for each class — normalized but expensive polymorphic queries. TABLE_PER_CLASS creates a full table per concrete class — flexible but inefficient for queries across hierarchies.

In production, SINGLE_TABLE is often preferred for simple hierarchies where subclasses have few additional fields. JOINED is better for deep hierarchies with many subclass-specific columns. Avoid TABLE_PER_CLASS due to slow UNION-based queries.

PaymentHierarchy.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package io.thecodeforge.entities;

import jakarta.persistence.*;

// Root entity
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "payment_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Payment {

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

    @Column(name = "amount", nullable = false, precision = 19, scale = 2)
    private java.math.BigDecimal amount;

    // Getters/Setters
}

@Entity
@DiscriminatorValue("CREDIT")
public class CreditCardPayment extends Payment {

    @Column(name = "card_last_four", length = 4)
    private String cardLastFour;

    @Column(name = "charge_id", length = 50)
    private String chargeId;

    // Getters/Setters
}

@Entity
@DiscriminatorValue("PAYPAL")
public class PayPalPayment extends Payment {

    @Column(name = "paypal_email")
    private String paypalEmail;

    // Getters/Setters
}
Output
Hibernate generates a single table: CREATE TABLE forge_payments (payment_type VARCHAR(31) NOT NULL, id BIGINT AUTO_INCREMENT, amount DECIMAL(19,2), card_last_four VARCHAR(4), charge_id VARCHAR(50), paypal_email VARCHAR(255), ...)
When to Use Each Strategy
SINGLE_TABLE: Best for small hierarchies with few subtype-specific columns. JOINED: Best when subclasses have many unique columns and you need normalized schema. TABLE_PER_CLASS: Rarely used — avoid unless you never query polymorphically.
Production Insight
SINGLE_TABLE: null columns waste storage and complicate NOT NULL constraints.
JOINED: polymorphic queries require joins — can be slow on large hierarchies.
Rule: start with SINGLE_TABLE and only move to JOINED when null columns become unmanageable.
Key Takeaway
SINGLE_TABLE is fast but wasteful.
JOINED is normalized but slower.
Avoid TABLE_PER_CLASS in production.

Performance Tuning and Production Best Practices

Beyond basic mappings, production systems need careful configuration. Enable Hibernate statistics via spring.jpa.properties.hibernate.generate_statistics=true to monitor query counts, flushes, and second-level cache hits. Use connection pooling (HikariCP) and configure batch insert/update sizes.

For read-heavy workloads, enable second-level cache with Redis or Ehcache, but be careful with cache invalidation. For write-heavy workloads, use JDBC batch processing and avoid flushing the persistence context too frequently. Disable hibernate.show_sql in production — it's a performance killer. Instead, use a logging appender or Datadog APM to trace slow queries.

application.propertiesPROPERTIES
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# io.thecodeforge production Hibernate configuration
spring.jpa.properties.hibernate.generate_statistics=true
spring.jpa.properties.hibernate.jdbc.batch_size=20
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true

# Second-level cache with Redis
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.jcache.JCacheRegionFactory
spring.jpa.properties.hibernate.javax.cache.provider=org.ehcache.jsr107.EhcacheCachingProvider

# Connection pool (HikariCP default)
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
Output
With batch_size=20, Hibernate groups INSERT statements into batches of 20, reducing database round trips by up to 95%.
Quick Win:
Set hibernate.jdbc.batch_size to 20-50 in your application.properties. This single property can reduce insertion time by an order of magnitude for bulk operations.
Production Insight
Enabling show_sql in production fills logs and slows down the application — never do it.
The persistence context grows unbounded in long-running sessions; clear it periodically.
Rule: use production-grade logging (e.g., Logback) with a dedicated SQL appender instead of show_sql.
Key Takeaway
Statistics are your first debugging tool.
Batch inserts dramatically improve throughput.
Disable show_sql in production — use structured logging.
● Production incidentPOST-MORTEMseverity: high

Missing mappedBy Causes Duplicate Foreign Key Columns

Symptom
When saving a Department with employees, Hibernate generated two separate UPDATE statements for the same foreign key column, causing a constraint violation error.
Assumption
The team assumed that using @OneToMany and @ManyToOne annotations on both sides would automatically be recognized as a single bidirectional relationship.
Root cause
Omitting the mappedBy attribute on the @OneToMany side made Hibernate treat both sides as owning entities, each trying to manage the foreign key independently.
Fix
Add mappedBy = "department" to the @OneToMany annotation in the Department entity, pointing to the field name in the Employee class.
Key lesson
  • Always define mappedBy on the inverse (non-owning) side of a bidirectional relationship.
  • The owning side is always the side that contains @JoinColumn.
  • Use an IDE plugin or Hibernate validation to detect missing mappedBy at compile time.
Production debug guideSymptom-driven debugging for the most common mapping failures4 entries
Symptom · 01
Hibernate creates unwanted additional tables
Fix
Check if a @ManyToMany relationship exists without mappedBy on either side. Use hibernate.show_sql=true to view generated DDL.
Symptom · 02
N+1 query problem when fetching entities
Fix
Examine logs for repeated SELECT statements. Replace FetchType.EAGER with FetchType.LAZY and use JOIN FETCH in JPQL or @EntityGraph.
Symptom · 03
Duplicate foreign key column in DDL
Fix
Verify that the inverse side of a bidirectional @OneToMany has the mappedBy attribute. Check for missing @JoinColumn on the owning side.
Symptom · 04
ConstraintViolationException on INSERT/UPDATE
Fix
Look for nullable=false on @Column but missing values, or cascade=CascadeType.PERSIST on a detached entity. Enable SQL logging and check bind parameters.
★ Hibernate Mapping Debug Cheat SheetQuick commands to diagnose mapping issues in production environments
Wrong table is being used
Immediate action
Check @Table annotation and entity class name vs actual table name in logs.
Commands
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Fix now
Add explicit @Table(name = "table_name") on the entity.
N+1 selects appear+
Immediate action
Check fetch strategy in entity relationships.
Commands
spring.jpa.properties.hibernate.generate_statistics=true
Check Hibernate statistics output for 'Entity load count' vs number of entities.
Fix now
Set FetchType.LAZY on the relationship and add @EntityGraph for specific queries.
Cannot insert because of missing ID+
Immediate action
Verify @Id and @GeneratedValue presence.
Commands
Check DDL: spring.jpa.hibernate.ddl-auto=validate
Run SELECT column_name FROM information_schema.columns WHERE table_name='your_table';
Fix now
Add @Id and @GeneratedValue(strategy=GenerationType.IDENTITY) for auto-increment.
Enum values are stored as numbers but expected strings+
Immediate action
Check Enum type mapping in entity.
Commands
SELECT DISTINCT status FROM forge_users;
Check @Enumerated annotation on enum field.
Fix now
Add @Enumerated(EnumType.STRING) on the field.
Hibernate vs Traditional JDBC
AspectTraditional JDBCHibernate (ORM)
Data TransferManual mapping via ResultSetAutomatic via Annotations
SQL GenerationHardcoded in Java stringsDynamic (Database Independent)
Relationship ManagementManual Join QueriesDeclarative (@OneToMany, etc.)
CachingMust be built manuallyBuilt-in L1 and L2 Caching
ComplexityLow (Initial) / High (Scale)Moderate (Learning Curve)

Key takeaways

1
Hibernate Entity Mapping is the bridge between Object-Oriented code and Relational Data, effectively handling the 'impedance mismatch'.
2
Always favor FetchType.LAZY to keep your application memory footprint small and prevent accidental database-wide loads.
3
Use @JoinColumn on the owning side of the relationship to manage foreign keys properly and maintain schema integrity.
4
Implement consistent naming strategies using @Table and @Column to ensure your io.thecodeforge microservices are portable across different DB environments.
5
Read the official JPA specification alongside the Hibernate documentation to understand the standards behind the annotations.
6
Map enums with @Enumerated(EnumType.STRING) to avoid silent data corruption on enum reordering.
7
Use batch processing (batch_size, order_inserts) to achieve near-JDBC throughput for bulk operations.

Common mistakes to avoid

4 patterns
×

Using FetchType.EAGER on One-to-Many collections

Symptom
Loading a single parent entity triggers multiple SQL queries (N+1) or a massive join that loads thousands of related records unnecessarily, causing memory exhaustion and slow response times.
Fix
Always use FetchType.LAZY on collections. For specific queries that need the association, use JOIN FETCH in JPQL or @EntityGraph.
×

Forgetting to implement equals() and hashCode() for entities

Symptom
Entities behave incorrectly in Sets (duplicate entries), detached entity comparison fails, and collection operations produce unexpected results.
Fix
Implement equals() and hashCode() using a business key (e.g., UUID or unique username) — not the database ID which may be null before persist.
×

Over-using @ManyToMany relationships without a middle Entity

Symptom
When you later need to add extra columns (like created_date or role_name) to the join table, you must refactor to a new entity, breaking existing code.
Fix
Map it as two @OneToMany relationships to an association entity instead. Create a dedicated entity for the join table and add columns there.
×

Using GenerationType.AUTO in production

Symptom
On MySQL, AUTO defaults to TABLE-based generation which uses a slow pessimistic lock on a separate sequence table, causing performance bottlenecks for high-concurrency INSERTs.
Fix
Use GenerationType.IDENTITY for MySQL/PostgreSQL (auto-increment) or GenerationType.SEQUENCE for Oracle/SQL Server with a proper sequence allocator.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
What is the difference between @PrimaryKeyJoinColumn and @JoinColumn in ...
Q02SENIOR
Explain the 'N+1 Select Problem' and how proper mapping and fetching str...
Q03SENIOR
When would you choose InheritanceType.JOINED over InheritanceType.SINGLE...
Q04SENIOR
What is the purpose of the 'mappedBy' attribute in a bidirectional relat...
Q05JUNIOR
How do you map a Java Enum to a database column? What is the difference ...
Q01 of 05SENIOR

What is the difference between @PrimaryKeyJoinColumn and @JoinColumn in a Hibernate inheritance mapping?

ANSWER
In inheritance, @PrimaryKeyJoinColumn is used in the JOINED strategy to specify that the child table's primary key is also a foreign key to the parent table's primary key. @JoinColumn is used in general relationships (e.g., @ManyToOne) to define the foreign key column. In JOINED inheritance, you don't need @JoinColumn — Hibernate uses @PrimaryKeyJoinColumn by default to join the tables.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What happens if I don't use the @Table annotation?
02
Can I map a single class to multiple tables?
03
How do I map a collection of basic types like Strings?
04
Is @Id mandatory for every entity?
05
What is the difference between CascadeType.ALL and CascadeType.PERSIST + CascadeType.MERGE?
06
How does the persistence context (L1 cache) affect transaction boundaries?
🔥

That's Hibernate & JPA. Mark it forged?

3 min read · try the examples if you haven't

Previous
Hibernate vs JPA — What's the Difference
3 / 7 · Hibernate & JPA
Next
One-to-Many and Many-to-Many in Hibernate