Entities & @Entity Basics
Entities & @Entity Basics
In Spring Data JPA, a persistent entity is a plain Java class that Hibernate maps to a relational database table. The mapping is declared entirely through annotations — no XML, no code generation step. This lesson walks through everything you need to create a correct, production-grade entity: the required annotations, the column-naming rules, identity strategies, and the performance trade-offs you must understand before you write your first save() call.
The Minimum Viable Entity
Two annotations are mandatory for every entity: @Entity marks the class as a JPA-managed type, and @Id designates the field that maps to the primary key column. Spring Boot 3 uses the jakarta.persistence package (Jakarta EE 9+), not the old javax.persistence one.
protected (not public) to discourage application code from calling it directly.
Table and Column Name Resolution
By default, Hibernate 6 derives the table name from the class name and the column name from each field name, using its configured ImplicitNamingStrategy. Spring Boot sets the strategy to SpringImplicitNamingStrategy, which converts camelCase to snake_case: a field named unitPrice becomes the column unit_price.
Use @Table and @Column when you need to override the defaults or constrain the schema:
nullable = false on non-optional columns. Hibernate can generate the DDL (spring.jpa.hibernate.ddl-auto=validate in CI) and it will flag missing NOT NULL constraints. This catches schema drift early rather than at runtime.
Primary Key Generation Strategies
Choosing the right @GeneratedValue strategy affects insert throughput, portability, and how you batch inserts. JPA defines four strategies through the GenerationType enum:
- AUTO (default): Hibernate picks a strategy based on the database dialect. On PostgreSQL it uses a sequence; on MySQL it falls back to a table generator. Avoid AUTO in production — its behaviour can change when you switch databases or upgrade Hibernate.
- IDENTITY: Delegates to the database's auto-increment column (
SERIAL/AUTO_INCREMENT). Simple, but breaks JDBC batch inserts because Hibernate must flush each row individually to retrieve its generated ID before it can cascade to child entities. - SEQUENCE (recommended for PostgreSQL / Oracle): Allocates a block of IDs from a database sequence in a single round-trip (
allocationSizecontrols the block size, default 50). Hibernate assigns IDs in memory and batchesINSERTs efficiently. - TABLE: A portable but slow fallback that uses a dedicated lock table. Avoid unless your database truly lacks sequences.
spring.jpa.properties.hibernate.jdbc.batch_size=50 in application.properties has no effect while IDENTITY is in use.
UUIDs as Primary Keys
For distributed systems or APIs where you want to expose entity IDs without leaking sequential information, a UUID primary key is a common pattern. Hibernate 6 natively supports java.util.UUID:
@UuidGenerator (Hibernate-specific) is preferred over @GeneratedValue(strategy = GenerationType.UUID) (JPA 3.1 standard) because it lets you control the UUID version. Both avoid a database round-trip, so bulk inserts batch correctly.
Basic Field Type Mappings
Hibernate maps the standard Java types to SQL types automatically. Key mappings to know:
String→VARCHAR(255)by default; override with@Column(length = N)or@Lobfor large text.int/Integer,long/Long→INTEGER/BIGINT.boolean/Boolean→BOOLEAN(orTINYINT(1)on MySQL).java.time.LocalDate,LocalDateTime,Instant→ native date/time columns. No@Temporalneeded in Hibernate 6.BigDecimal→DECIMAL; always use for monetary values — neverdoubleorfloatin financial columns.- Enums: annotate with
@Enumerated(EnumType.STRING)to store the name ("ACTIVE") rather than the ordinal (0), which breaks if the enum order changes.
equals() and hashCode() for Entities
Hibernate places entities in Set collections and compares them during dirty checking. The default Object.equals() (identity comparison) can produce subtle bugs when the same database row is loaded in two separate EntityManager sessions. The recommended approach is to base equality on the natural business key (e.g. sku) rather than the surrogate ID, because the surrogate ID is null before the first save().
Summary
An entity is a plain Java class annotated with @Entity and a single @Id field. Use @Table and @Column to document and constrain the schema. Pick a generation strategy deliberately: SEQUENCE for throughput, IDENTITY for simplicity, UUID for distributed systems. Use BigDecimal for money, @Enumerated(EnumType.STRING) for enums, and the modern java.time types for dates. Define equals() on a business key, not the surrogate ID. With these foundations in place you are ready to explore the repository abstraction in the next lesson.