Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Columns and types

By default Hibernate makes a column from every field: the name of the field, a suitable type, varchar(255) for strings. That is enough to start, but a real table needs more: required columns, string lengths, its own names. All of this is set with annotations on the fields.

A richer Post

// src/main/java/com/example/blog/PostStatus.java
package com.example.blog;
 
public enum PostStatus {
    DRAFT, PUBLISHED, ARCHIVED
}
// src/main/java/com/example/blog/Post.java
package com.example.blog;
 
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import java.time.LocalDateTime;
 
@Entity
@Table(name = "posts")
public class Post {
 
    @Id
    @GeneratedValue
    private Long id;
 
    @Column(nullable = false, length = 200)
    private String title;
 
    @Column(length = 10_000)
    private String body;
 
    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private PostStatus status = PostStatus.DRAFT;
 
    @Column(name = "published_at")
    private LocalDateTime publishedAt;
 
    private int views;
 
    @Transient
    private boolean selected;
 
    protected Post() {
    }
 
    public Post(String title, String body) {
        this.title = title;
        this.body = body;
    }
 
    public void publish() {
        status = PostStatus.PUBLISHED;
        publishedAt = LocalDateTime.of(2026, 3, 15, 10, 0);
    }
 
    // getters
}

Hibernate creates this table:

Hibernate: create table posts (views integer not null, id bigint not null, published_at timestamp(6), title varchar(200) not null, body varchar(10000), status enum ('ARCHIVED','DRAFT','PUBLISHED') not null, primary key (id))
AnnotationWhat it does
@Table(name = "posts")Table name instead of the class name
@Column(name = "published_at")Column name instead of the field name
nullable = falseAdds not null
length = 200String length: varchar(200)
@Enumerated(EnumType.STRING)Store the enum constant by its name
@TransientDo not store the field at all

H2 and MySQL have a special enum column type; in PostgreSQL the same mapping gives a varchar column with a check of allowed values.

Java types and SQL types

JavaSQL (H2)
Stringvarchar(255)
int, longinteger not null, bigint not null
booleanboolean not null
BigDecimalnumeric(38,2)
LocalDatedate
LocalDateTimetimestamp(6)
Instanttimestamp(6) with time zone

Primitive types always get not null, because a primitive cannot hold null. For money use BigDecimal, not double. For long texts there is also @Lob, which gives a clob column.

Checking the stored values

// src/main/java/com/example/blog/Main.java
emf.runInTransaction(em -> {
    Post post = new Post("Column mapping", "Types, enums and dates");
    post.publish();
    em.persist(post);
});
 
Object[] row = emf.callInTransaction(em -> (Object[]) em
        .createNativeQuery("select title, status, published_at, views from posts")
        .getSingleResult());
IO.println(java.util.Arrays.toString(row));

The program reads the row with plain SQL and prints it:

[Column mapping, PUBLISHED, 2026-03-15T10:00, 0]

The status is stored as the text PUBLISHED, the date as a timestamp.

Common mistake

Without @Enumerated(EnumType.STRING) an enum is stored as its position number:

Hibernate: create table posts (status tinyint not null check ((status between 0 and 2)), ...)

DRAFT becomes 0, PUBLISHED becomes 1. If someone later adds a constant at the start of the enum, all old rows silently change their meaning. Always write @Enumerated(EnumType.STRING).

Thanks for reading!

Donate to the site — we work hard for you.