Modern Hibernate applications use the jakarta.persistence API, not the old javax.persistence package. With Hibernate ORM 7 and Jakarta Persistence 3.2, most simple entity fields are mapped automatically, while annotations such as @Table, @Column and @Transient let you customize the mapping when the defaults are not enough.
The basic rule is simple: a persistent field on an @Entity normally maps to a database column automatically. You only need @Column when you want to change that default mapping or provide schema-generation metadata.
Hibernate 7 and Jakarta Persistence 3.2
The current stable Hibernate ORM 7.4 series implements Jakarta Persistence 3.2 and requires Java 17 or newer. A Maven project that uses Hibernate directly can declare Hibernate ORM like this:
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>7.4.6.Final</version>
</dependency>If a framework such as Quarkus manages Hibernate for you, let the framework's dependency-management system choose the compatible Hibernate version instead of overriding it manually.
Default JPA column mapping
Consider this minimal entity:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Player {
@Id
@GeneratedValue
private Long id;
private String loginName;
private String password;
protected Player() {
}
}With field access, Hibernate treats the persistent fields as entity attributes. Jakarta Persistence supplies sensible defaults for their mappings. The actual physical table and column names can also be affected by Hibernate naming strategies, so production applications often use explicit names when the database schema matters.
Rename a database column with @Column
Suppose the Java field is named loginName, but the database column must be named login_name. Add @Column(name = "login_name"):
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "player")
public class Player {
@Id
@GeneratedValue
private Long id;
@Column(name = "login_name")
private String loginName;
private String password;
protected Player() {
}
}The explicit @Table annotation removes ambiguity about the table name, while @Column maps the Java attribute loginName to the SQL column login_name.
The JPA @Column annotation customizes how an entity attribute maps to a database column.
Modern @Column options
Jakarta Persistence 3.2 provides a richer @Column annotation than older JPA releases. Important members include:
| Member | Purpose |
|---|---|
name | Overrides the mapped database column name. |
nullable | Declares whether the generated database column may contain NULL. |
unique | Declares a single-column unique constraint during schema generation. |
length | Specifies the length for length-parameterized column types such as VARCHAR. |
precision | Specifies precision for exact numeric columns such as DECIMAL. |
scale | Specifies scale for exact numeric columns such as DECIMAL. |
secondPrecision | Controls fractional-second precision for time and timestamp columns. |
insertable | Controls whether Hibernate includes the column in generated INSERT statements. |
updatable | Controls whether Hibernate includes the column in generated UPDATE statements. |
table | Specifies the table containing the column when secondary tables are involved. |
columnDefinition | Supplies database-specific DDL for the column. |
options | Appends a database-specific SQL fragment to generated DDL. |
check | Adds schema-generation check constraints. |
comment | Adds a database-column comment during schema generation. |
The options, check, comment and secondPrecision members are particularly relevant to modern Jakarta Persistence 3.2 applications.
Column length, nullability and uniqueness
A typical user-facing field might have several mapping requirements:
@Column(
name = "handle",
nullable = false,
unique = true,
length = 40
)
private String name;This tells the persistence provider that schema generation should map the attribute to a column named handle, make it non-nullable, constrain it to the requested length and create a single-column uniqueness constraint.
These settings primarily describe persistence and schema metadata. They are not a replacement for application-level validation. If the Java application must reject blank or oversized input before SQL is issued, use Jakarta Validation annotations such as @NotBlank and @Size as well.
Precision and scale for decimal values
For exact decimal values, use BigDecimal together with explicit precision and scale:
import java.math.BigDecimal;
@Column(
name = "account_balance",
precision = 12,
scale = 2,
nullable = false
)
private BigDecimal accountBalance;A precision of 12 allows up to 12 total decimal digits, while a scale of 2 reserves two digits to the right of the decimal point. Jakarta Persistence recommends explicitly specifying precision and scale when portable schema generation for DECIMAL or NUMERIC values matters.
Timestamp precision in Jakarta Persistence 3.2
Jakarta Persistence 3.2 adds secondPrecision for time and timestamp columns. For example:
import java.time.LocalDateTime;
@Column(secondPrecision = 3)
private LocalDateTime lastLogin;This requests three fractional-second digits when schema generation is used and the underlying database supports the requested precision.
Check constraints and comments
Jakarta Persistence 3.2 also lets schema-generation metadata include column comments and check constraints:
import jakarta.persistence.CheckConstraint;
import jakarta.persistence.Column;
@Column(
name = "score",
nullable = false,
check = @CheckConstraint(
constraint = "score >= 0 AND score <= 100"
),
comment = "Player score from 0 through 100"
)
private int score;These declarations matter when the persistence provider is responsible for generating or updating DDL. If your production schema is managed with a migration tool, the migration scripts remain the authoritative source of database constraints.
Use columnDefinition carefully
The columnDefinition member lets you take direct control over generated SQL:
@Column(
name = "profile_json",
columnDefinition = "json"
)
private String profileJson;This can be useful when the database has a native type that is not represented by portable JPA metadata, but it comes with a tradeoff: the DDL fragment is database-specific. A declaration written for MySQL might not work on PostgreSQL, Oracle or another database.
Use portable mapping metadata when possible, and use columnDefinition only when you intentionally accept database coupling.
insertable and updatable
The insertable and updatable flags control whether a mapped attribute participates in generated SQL INSERT and UPDATE statements.
For example, if the database assigns a value and the application should never update it:
@Column(
name = "created_by_database",
insertable = false,
updatable = false
)
private String createdByDatabase;These flags do not make a Java field immutable. They only change how the persistence provider includes the mapped column in generated SQL.
A modern Hibernate entity example
Here is a more complete entity using modern Jakarta Persistence imports and several column-mapping features:
import java.math.BigDecimal;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
@Entity
@Table(
name = "player",
schema = "hibernate_examples"
)
public class Player {
@Id
@GeneratedValue
private Long id;
@Column(
name = "handle",
nullable = false,
unique = true,
length = 40
)
private String name;
@Column(
name = "email_address",
nullable = false,
length = 254
)
private String emailAddress;
@Column(nullable = false)
private boolean verified;
@Column(nullable = false, length = 255)
private String passwordHash;
@Column(
name = "account_balance",
precision = 12,
scale = 2,
nullable = false
)
private BigDecimal accountBalance;
@Column(secondPrecision = 3)
private LocalDateTime lastLogin;
@Transient
private String plainTextPassword;
protected Player() {
}
}This mapping makes the intent explicit:
- The entity maps to
hibernate_examples.player. idis the generated primary key.namemaps to a unique, non-nullhandlecolumn.emailAddressmaps explicitly toemail_address.accountBalanceuses an exact decimal mapping.lastLoginrequests millisecond-level fractional-second precision.plainTextPasswordis not persistent.
How @Transient works
The Jakarta Persistence @Transient annotation tells Hibernate that an attribute is not persistent:
@Transient
private String plainTextPassword;Hibernate does not create a mapped column for the attribute and does not include it in persistence operations.
This is different from the Java transient keyword. The Java keyword controls Java object serialization. JPA's @Transient annotation explicitly controls persistence mapping.
Field access vs. property access
Where you place @Id determines the default JPA access strategy for an entity.
If @Id is on a field, Hibernate uses field access and mapping annotations normally belong on fields:
@Id
@GeneratedValue
private Long id;If @Id is placed on a getter, the entity uses property access and mapping annotations normally belong on getter methods instead.
Be consistent. Mixing field and property annotations without deliberately using @Access can make mappings difficult to understand.
Modern Hibernate column mapping rules
The practical rules for Hibernate ORM 7 and Jakarta Persistence 3.2 are straightforward:
- Import persistence annotations from
jakarta.persistence, notjavax.persistence. - Let simple fields use default mappings unless the database contract requires customization.
- Use
@Tableand@Column(name = ...)when physical names matter. - Use
BigDecimalwith explicitprecisionandscalefor exact decimals. - Use
@Transientfor fields that must not be persisted. - Treat
columnDefinitionandoptionsas database-specific escape hatches. - Remember that schema metadata such as
nullableis not a substitute for Jakarta Validation. - Use Jakarta Persistence 3.2 features such as
secondPrecision,checkandcommentwhen they improve generated schema definitions.
Hibernate's defaults eliminate a lot of repetitive mapping code, while modern Jakarta Persistence annotations give you precise control when the Java model and relational schema need to differ.