A Hibernate SessionFactory is the main factory for Hibernate Session instances. It is expensive to create, thread-safe, and normally created once for the lifetime of an application.
This tutorial updates the older Hibernate 5 examples to Hibernate ORM 7.4 and Jakarta Persistence 3.2. Hibernate 7.4 requires Java 17 or newer.
There are three useful ways to obtain a Hibernate SessionFactory:
- Bootstrap Hibernate with
Configurationandhibernate.cfg.xml. - Bootstrap Hibernate programmatically with
StandardServiceRegistryandMetadataSources. - Bootstrap with Jakarta Persistence and unwrap Hibernate's
SessionFactoryfrom theEntityManagerFactory.
Hibernate 7.4 Maven dependency
Hibernate recommends using its platform BOM to keep Hibernate artifact versions aligned.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-platform</artifactId>
<version>7.4.6.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.4.0</version>
</dependency>
</dependencies>Hibernate 7 uses the jakarta.persistence APIs. Entity classes should therefore import annotations such as jakarta.persistence.Entity and jakarta.persistence.Id, not the old javax.persistence package.
What is a Hibernate SessionFactory?
SessionFactory represents a configured Hibernate instance. It owns the runtime mapping metadata, services, cache configuration and database integration required to create Hibernate sessions.
Applications normally create a single SessionFactory and then open a short-lived Session for each unit of work or transaction.
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
// Perform persistence work here.
session.getTransaction().commit();
}Modern Hibernate also provides transaction helper methods that can reduce some of this ceremony.
sessionFactory.inTransaction(session -> {
// Perform persistence work here.
});1. Build SessionFactory with hibernate.cfg.xml
The traditional Hibernate bootstrap approach uses a hibernate.cfg.xml file on the classpath.
A Hibernate 7 configuration for MySQL can look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"https://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/hibernate_examples
</property>
<property name="hibernate.connection.username">
root
</property>
<property name="hibernate.connection.password">
password
</property>
<property name="hibernate.show_sql">
true
</property>
<property name="hibernate.format_sql">
true
</property>
<mapping class="com.mcnz.jpa.examples.Player"/>
</session-factory>
</hibernate-configuration>Two settings from older examples are deliberately absent. Modern JDBC drivers are normally discovered automatically, so explicitly configuring com.mysql.jdbc.Driver is unnecessary. Hibernate can also usually determine the database dialect from JDBC metadata, so hard-coding an old MySQL8Dialect is normally unnecessary.
The SessionFactory can then be built with Hibernate's Configuration API:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public final class HibernateUtil {
private static final SessionFactory SESSION_FACTORY =
new Configuration()
.configure()
.buildSessionFactory();
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return SESSION_FACTORY;
}
}This approach remains convenient for small native-Hibernate applications that prefer XML configuration.
2. Build SessionFactory without Hibernate XML
If you prefer Java configuration, Hibernate's native bootstrap APIs let you build the same infrastructure programmatically.
First create a map containing the database settings:
Map<String, Object> settings = new HashMap<>();
settings.put(
"hibernate.connection.url",
"jdbc:mysql://localhost:3306/hibernate_examples"
);
settings.put(
"hibernate.connection.username",
"root"
);
settings.put(
"hibernate.connection.password",
"password"
);
settings.put(
"hibernate.show_sql",
"true"
);
settings.put(
"hibernate.format_sql",
"true"
);Then apply those settings to a StandardServiceRegistry, register the mapped entities with MetadataSources, build the metadata and finally build the factory:
import java.util.HashMap;
import java.util.Map;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class HibernateBootstrap {
public static SessionFactory buildSessionFactory() {
Map<String, Object> settings = new HashMap<>();
settings.put(
"hibernate.connection.url",
"jdbc:mysql://localhost:3306/hibernate_examples"
);
settings.put(
"hibernate.connection.username",
"root"
);
settings.put(
"hibernate.connection.password",
"password"
);
settings.put(
"hibernate.show_sql",
"true"
);
StandardServiceRegistry registry =
new StandardServiceRegistryBuilder()
.applySettings(settings)
.build();
try {
Metadata metadata =
new MetadataSources(registry)
.addAnnotatedClass(Player.class)
.buildMetadata();
return metadata.buildSessionFactory();
} catch (RuntimeException e) {
StandardServiceRegistryBuilder.destroy(registry);
throw e;
}
}
}This is the modern equivalent of the old ServiceRegistry and Metadata approach. The overall bootstrap model is still recognizable, but the example no longer uses obsolete driver names, old dialect classes or Hibernate 5-specific comments.
3. Get SessionFactory from Jakarta Persistence
Hibernate's native API and Jakarta Persistence are closely integrated. In Hibernate 7, SessionFactory extends Jakarta Persistence's EntityManagerFactory, and Hibernate's Session extends EntityManager.
If an application bootstraps Hibernate through Jakarta Persistence, the cleanest way to obtain the native Hibernate factory is to unwrap it directly from the EntityManagerFactory.
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import org.hibernate.SessionFactory;
public class JpaHibernateBootstrap {
public static SessionFactory buildSessionFactory() {
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory(
"jpa-tutorial"
);
return entityManagerFactory.unwrap(
SessionFactory.class
);
}
}The older pattern of creating an EntityManager, unwrapping a Hibernate Session and then calling getSessionFactory() still illustrates the relationship between the APIs, but it is unnecessarily indirect when all you want is the factory.
Jakarta Persistence 3.2 persistence.xml example
A Jakarta Persistence bootstrap typically uses a META-INF/persistence.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<persistence
xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://jakarta.ee/xml/ns/persistence
https://jakarta.ee/xml/ns/persistence/persistence_3_2.xsd"
version="3.2">
<persistence-unit name="jpa-tutorial">
<provider>
org.hibernate.jpa.HibernatePersistenceProvider
</provider>
<class>
com.mcnz.jpa.examples.Player
</class>
<properties>
<property
name="jakarta.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/hibernate_examples"/>
<property
name="jakarta.persistence.jdbc.user"
value="root"/>
<property
name="jakarta.persistence.jdbc.password"
value="password"/>
<property
name="hibernate.show_sql"
value="true"/>
</properties>
</persistence-unit>
</persistence>SessionFactory vs. EntityManagerFactory
| Hibernate API | Jakarta Persistence API |
|---|---|
SessionFactory |
EntityManagerFactory |
Session |
EntityManager |
With Hibernate as the persistence provider, these APIs are not isolated worlds. Hibernate's SessionFactory is itself an EntityManagerFactory, and a Hibernate Session is itself an EntityManager.
For portable application code, prefer Jakarta Persistence APIs when they provide everything you need. Use the Hibernate native interfaces when the application needs Hibernate-specific capabilities.
Which Hibernate SessionFactory approach is best?
| Approach | Best fit |
|---|---|
Configuration + hibernate.cfg.xml |
Simple native-Hibernate applications that prefer XML |
MetadataSources + StandardServiceRegistry |
Programmatic native-Hibernate bootstrap |
Jakarta Persistence + unwrap() |
Applications primarily written against JPA/Jakarta Persistence |
For a new application, the Jakarta Persistence approach usually provides the most portable API. If the application deliberately uses Hibernate-specific functionality, native bootstrap with Configuration or MetadataSources remains completely valid.
Whichever approach you use, build the SessionFactory once, keep it for the application lifetime, create short-lived sessions for individual units of work, and close the factory during application shutdown.