Hibernate ORM has a huge API surface, but here’s a list of the most fundamental session operations and O/R mappings that you’ll need all the time.
Stateful sessions
A Hibernate Session
or JPA EntityManager
represents a stateful persistence context.
That is, it maintains a set of associated entities, automatically detects modifications made to the entities, and propagates such modifications to the database.
#1 find
The find()
method fetches the entity with the given primary key from the database.
var book = session.find(Book.class, isbn)
The returned entity is associated with the persistence context, and so any modifications you make its state will be automatically propagated to the database when the session flushes.
You can call evict()
to remove it from the persistence context.
Optionally, find()
accepts one or more FindOption
s, customizing locking, timeout, or interaction with the second-level cache.
var book = session.find(Book.class, isbn,
LockModeType.PESSIMISTIC_WRITE,
CacheStoreMode.BYPASS)
The find()
method even accepts an EntityGraph
, allowing you to specify the associations you would like to fetch.
#2 persist
The persist()
method add an entity to the persistence context, and schedules it for insertion in the database.
session.persist(book);
The actual insertion doesn’t happen until the session flushes.
#3 refresh
The refresh()
method overwrites the state of the given entity with the current persistent state held by the database.
session.refresh(book)
#4 lock
The lock()
method may be used to upgrade the current lock mode of an entity.
session.lock(book, LockModeType.PESSIMISTIC_FORCE_INCREMENT)
#5 merge
The merge()
method merges the state of an entity which is not associated with the persistence context into the current persistence context.
var managedBook = session.merge(detachedBook);
A call to merge()
returns an entity associated with the persistence context, with the same state as the entity passed as an argument to merge()
.
#6 remove
The remove()
method schedules an entity for deletion from the database.
session.remove(book);
The actual deletion doesn’t happen until the session flushes.
#7 selection queries
Selection queries retrieve data from the database.
var books =
session.createSelectionQuery("where title like :title order by publicationDate", Book.class)
.setParameter("title", title);
.setMaxResults(50)
.getResultList();
The entities returned in the query result set are associated with the persistence context.
#8 mutation queries
Mutation queries update or delete data.
session.createMutationQuery("update Order set status = PROCESSED, processed = local datetime where status = IN_PROCESS")
.executeUpdate();
#9 criteria queries
A criteria query is a query constructed programmatically.
var query = builder.createQuery(Book.class);
var book = query.from(Book.class);
var where = builder.conjunction();
if (titlePattern != null) {
where = builder.and(where, builder.like(book.get(Book_.title), titlePattern));
}
if (namePattern != null) {
var author = book.join(Book_.author);
where = builder.and(where, builder.like(author.get(Author_.name), namePattern));
}
query.select(book).where(where)
.orderBy(builder.asc(book.get(Book_.title)));
#10 native queries
Native queries let you write a query in the native SQL dialect of your database, map its result set to Java objects, and execute the SQL via Hibernate. In older versions of Hibernate, native SQL queries were used quite often—but since Hibernate 6, HQL is so powerful that they’re now rarely needed.
Stateless sessions
The StatelessSession
offers a simplified programming model, allowing more direct control over interaction with the database.
A stateless session doesn’t have an associated persistence context, and so a change is only made to the database when you explicitly ask for it.
If you find yourself juggling the flush() , detach() , and clear() methods of a stateful session, that’s a sure indication that you might be better off going stateless.
|
#1 get
The get()
method retrieves an entity from the database, but doesn’t associate it with any persistence context.
var book = session.get(Book.class, isbn)
Optionally, you can specify a LockMode
, or an EntityGraph
.
#3 update
The update()
operation immediately updates the database.
session.update(book);
For a stateless session, updates to the database never happen automatically.
#4 upsert
The upsert()
operation results in execution of a SQL MERGE
statement.
session.upsert(book);
#5 delete
The delete()
operation immediately deletes the entity from the database.
session.delete(book);
#6 fetch
The fetch()
method initializes an unfetched association.
session.fetch(book.getAuthors());
For a stateless session, lazy fetching never happens transparently nor by accident.
Common mappings
Hibernate has an incredibly rich set of annotations for mapping Java classes to relational database tables, but you’ll only need a tiny fraction of them.
In fact, you’re more likely to have success with Hibernate if you avoid the use of more exotic mappings until you run into a situation where you really need one. |
#1 Entity classes
An entity class is a plain Java class that maps a database table.
We know when something is an entity because it’s annotated @Entity
.
@Entity
class Book { ... }
You can explicitly specify the name of the mapped database table using @Table
.
@Entity
@Table(name="books")
class Book { ... }
The @SecondaryTable
annotation lets us map the fields of a single entity class across multiple tables.
#2 Entity inheritance
An entity may inherit a second entity.
@Entity
class Book extends Document { ... }
@Entity
class Document { ... }
By default, the two entities map the same database table.
If we have a normalized database schema, we can use @Inheritance(strategy=JOINED)
.
@Entity
@Table(name = "books")
class Book extends Document { ... }
@Entity
@Inheritance(strategy=JOINED)
@Table(name = "documents")
class Document { ... }
A third option is @Inheritance(strategy=TABLE_PER_CLASS)
.
You can learn more about inheritance mappings here.
#3 Basic attributes
A basic attribute is a field or property of a Java class which maps a column of a database table.
Usually, the type of the field or property is a primitive type like boolean
, int
, double
, or byte[]
, or a type that comes built-in to Java, like String
, BigDecimal
, or LocalDateTime
.
String name;
You can specify the mapped column using the @Column
annotation.
@Column(name="author_name")
String name;
If you have a field or property that maps to a single column, but its type isn’t one of the basic types build in to Hibernate, you can use an AttributeConverter
.
#4 Identifiers
An entity must have an identifier mapping the primary key of the database table.
@Id
String isbn;
If the primary key is a surrogate key, you can let Hibernate or the database itself generate the identifier.
@Id @GeneratedValue
UUID id;
On the other hand, in a schema which uses natural keys, we often need to map a composite primary key using @EmbeddedId
or @IdClass
.
You can read about these options here.
#5 Versions and timestamps
The @Version
annotation declares a field which is used for automatic optimistic locking.
@Version
LocalDateTime lastUpdated;
#6 Associations
There’s quite a range of different kinds of association mapping, but most of the time all you need is a bidirectional one-to-many association.
@Entity
class Book {
@Id
String isbn;
@ManyToOne(fetch=LAZY)
Publisher publisher;
}
@Entity
class Publisher {
@Id @GeneratedValue
Long id;
@OneToMany(mappedBy=Book_.PUBLISHER)
List<Book> books;
}
You may use @JoinColumn
to specify the foreign key mapping.
@Entity
class Book {
@Id
String isbn;
@ManyToOne(fetch=LAZY)
@JoinColumn(name = "book_publisher_id",
referencedColumnName = "publisher_id")
Publisher publisher;
}
@Entity
class Publisher {
@Id @GeneratedValue
@Column(name = "publisher_id")
Long id;
@OneToMany(mappedBy=Book_.PUBLISHER)
List<Book> books;
}
You can learn all about association mappings here.
#7 Embeddable classes
Some fine-grained Java classes don’t map to their own database table.
Instead, each instance of the class belongs to an entity, and the fields of the class map columns of the table mapped by the owning entity.
We declare such classes using the @Embeddable
annotation.
@Embeddable
class Name {
String first;
String last;
Character initial;
}
@Entity
class Author {
@Id
String ssn;
Name name;
}
You can read more about embeddable classes here. An embeddable class may even be mapped to a database UDT or JSON type.
#8 Enumerated types
A Java enum
might map a tinyint
column holding its ordinal value, or a varchar
column holding its name.
The @Enumerated
annotation selects between the two options.
@Enumerated(STRING)
DayOfWeek dayOfWeek;
Alternatively, on MySQL, PostgreSQL, or Oracle, a Java enum
might map to a database enum type.
#9 Collections and arrays
A collection or array might map a separate database table, or even a native SQL array
type.
It’s easy to overuse these mappings. |