Column Mapping — Extremely Important
Column mapping is about telling JPA/Hibernate: How should a Java field/property be represented in the database?
For example, take a look at this basic entity:
@Entity
public class Employee {
@Id
private Long id;
private String name;
private double salary;
}
Conceptually, this maps directly from Java to the Database:
Java Database
Employee employee
| |
|-- id ───────────→ id
|-- name ───────────→ name
|-- salary ───────────→ salary
JPA provides several annotations to control this mapping. Let's break them down.
1.1 @Column
@Column is used to customize how a Java field/property maps to a database column. Without it, the provider's default naming rules determine the column name.
Example:
@Column(name = "employee_name")
private String name;
Now, the Java field name maps to the Database column employee_name.
Common @Column attributes:
@Column(
name = "employee_name",
nullable = false,
unique = true,
length = 100
)
private String name;
The most important attributes are name, nullable, unique, length, precision, and scale. We'll understand each.
1.2 name
The name attribute is useful when your Java naming and database naming are different.
@Column(name = "employee_name")
private String employeeName;
1.3 nullable
@Column(nullable = false)
private String name;
Conceptually this means the database column should not accept NULL. When schema generation is used, this results in a constraint conceptually like: name VARCHAR(255) NOT NULL.
Important distinction
nullable = false is primarily database schema metadata. It is not the same as application-level validation. For example, @NotNull is Bean Validation, whereas nullable = false describes the database column constraint. For robust applications, you may use both when appropriate.
1.4 unique
@Column(unique = true)
private String email;
This indicates that the column should contain unique values. If schema generation is used, this creates a unique constraint/index depending on the database.
Important production point
For an important business uniqueness rule (such as email uniqueness), you generally want a real database unique constraint, not just application code checks. Concurrent requests can easily bypass a simple "if exists" check. The database should enforce the final constraint.
1.5 length
length is mainly relevant to string columns. It defines the maximum database string length when schema generation applies this metadata.
@Column(length = 100)
private String name;
Conceptually, this maps to name VARCHAR(100). Remember, it is primarily about database definition, not a complete replacement for input validation (like @Size(max = 100)).
1.6 precision & 1.7 scale
These are mainly relevant to numeric values such as BigDecimal.
@Column(precision = 10, scale = 2)
private BigDecimal salary;
- Precision: Total number of digits.
- Scale: Number of digits after the decimal point.
For a value like 12345678.90, you have 8 digits before the decimal and 2 digits after the decimal, equaling 10 total digits. Therefore, precision = 10 and scale = 2.
1.8 Precision vs Scale
This is a common interview question. Remember:
- PRECISION = total digits
- SCALE = digits after decimal
1.9 Complete @Column Example
@Column(
name = "salary",
nullable = false,
precision = 12,
scale = 2
)
private BigDecimal salary;
Conceptually, this generates salary DECIMAL(12,2) NOT NULL (the exact SQL type depends on the dialect).
1.10 @Basic
@Basic represents a basic persistent attribute. However, the most important point is: You usually don't need to write @Basic.
private String name;
This is already treated as a basic persistent attribute under normal JPA rules. It does have optional and fetch attributes, but lazy loading for basic attributes is provider-dependent.
1.11 @Transient
This one is extremely important. @Transient means: Do not persist this field as part of the entity's database state.
@Transient
private double bonus;
If you have a calculated field like a bonus, you can calculate it in Java (bonus = salary * 0.10), but the database table will not have a bonus column.
1.12 @Transient vs Java transient
This is a very common interview trap.
- JPA @Transient: Don't persist this field to the database.
- Java transient keyword: Exclude this field from Java serialization.
They solve entirely different problems.
1.13 @Lob
@Lob means: Map the attribute as a large object (LOB) in the database.
- Character data:
@Lob private String description;(Maps to CLOB, TEXT, etc.) - Binary data:
@Lob private byte[] document;(Maps to BLOB)
Note: In many modern applications, large files are better stored in object storage (S3, Azure) with URLs stored in the relational DB.
1.14 & 1.15 & 1.16 @Enumerated
When mapping an Enum to the database, you use @Enumerated. There are two main strategies:
EnumType.ORDINAL
@Enumerated(EnumType.ORDINAL)
private EmployeeStatus status;
The enum's numeric position (0, 1, 2) is stored. Problem: If you add a new enum value in the middle, the numbers shift, and existing database values will be interpreted incorrectly. Ordinal storage is risky for business enums.
EnumType.STRING
@Enumerated(EnumType.STRING)
private EmployeeStatus status;
The text name (e.g., "ACTIVE") is stored. This is much safer and more readable. Interview recommendation: For business enums, STRING is usually preferred; use ORDINAL carefully.
1.17, 1.18 & 1.19 @Temporal & Modern Dates
Historically, @Temporal(TemporalType.DATE) was used with legacy Java date types like java.util.Date and java.util.Calendar.
With modern Java (8+), we use LocalDate, LocalTime, LocalDateTime, Instant, etc. Modern JPA providers support these directly, so you generally do not use @Temporal with them.
private LocalDate joiningDate;
private LocalDateTime createdAt;
The modern java.time API is preferred because it's easier to reason about, provides clearer types, and handles timezones gracefully in distributed systems.
1.20 Complete Example
Let's put the important column mappings together:
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "employee_name", nullable = false, length = 100)
private String name;
@Column(nullable = false, precision = 12, scale = 2)
private BigDecimal salary;
@Column(unique = true)
private String email;
@Enumerated(EnumType.STRING)
private EmployeeStatus status;
private LocalDate joiningDate;
private LocalDateTime createdAt;
@Lob
private String description;
@Transient
private double calculatedBonus;
}
1.21 Quick Comparison
| Annotation / Attribute | Purpose |
|---|---|
@Column | Customize column mapping |
name | Specify column name |
nullable | Whether DB column may contain NULL |
unique | Unique constraint metadata |
length | String column length |
precision | Total digits for numeric values |
scale | Digits after decimal |
@Basic | Marks/configures a basic persistent attribute; usually implicit |
@Transient | Excludes field from persistence |
@Lob | Maps large text/binary data |
@Enumerated | Maps Java enum to DB |
EnumType.STRING | Stores enum name |
EnumType.ORDINAL | Stores enum position |
@Temporal | Legacy Date/Calendar temporal mapping |
java.time | Modern date/time mapping; normally no @Temporal |
Final Mental Model Summary
- @Column: Control DB column metadata (name, length, constraints).
- @Transient: Do not persist this field in the database.
- @Lob: Used for Large Objects (CLOB/BLOB text or binary).
- @Enumerated: Used for Enum mapping (Prefer
STRINGoverORDINAL). - @Temporal: Legacy. Use modern
LocalDate/LocalDateTimewithout it. - Precision & Scale: Precision is total digits, Scale is decimal digits.
The next important piece after this is @Access (FIELD vs PROPERTY) and how Hibernate decides whether it reads fields or getters/setters!
5.22 T3 Interview Questions (FAQs)
@Column controls database column mapping and schema-related attributes such as name, nullability, uniqueness, length, precision, and scale. @Basic describes a basic persistent attribute and is usually implicit, so it is rarely necessary to write explicitly.
JPA's @Transient stops a field from being persisted to the database. Java's transient keyword stops a field from being included in standard Java serialization. They are unrelated mechanisms.
Because ordinal values depend on enum positions. If enum constants are reordered or inserted, existing numeric database values can represent the wrong enum constant. STRING stores names such as "ACTIVE", which is generally safer for persistent business data.
Precision is the total number of digits. Scale is the number of digits after the decimal point. For 123456.78, precision = 8 and scale = 2.
No. @Temporal is for legacy temporal types such as java.util.Date and Calendar. Modern Java time types (LocalDate, LocalDateTime, Instant) are mapped directly by modern JPA providers.
No, not by itself. It primarily describes the database column constraint. For request validation, use Bean Validation where appropriate (like @NotNull) and use the database constraint as the final integrity boundary.
Comments (0)