Core Java

Using StatelessSession in Hibernate

When working with Hibernate, we usually interact with the Session interface. A session represents a single unit of work with the database and provides essential services, including first-level caching, automatic dirty checking, and transaction management. With a regular session, Hibernate tracks the state of entities, ensuring that any changes made in Java objects are synchronized with the database.

While this behaviour is convenient for most applications, it comes with additional overhead. For certain use cases such as batch inserts, bulk updates, or read-only operations, we may not need Hibernate to track entities or cache them. In such scenarios, Hibernate offers a lighter alternative called StatelessSession.

A StatelessSession is similar to working directly with JDBC. It does not maintain a persistence context, does not provide first-level caching, does not perform dirty checking, and does not support lazy loading or cascading operations. However, it still allows us to use Hibernate mappings, entity classes, and HQL queries. This makes it highly effective for performance-intensive operations where efficiency takes priority over the conveniences of a fully managed session.

In this article, we will build a simple example that demonstrates how to use StatelessSession for batch inserts and queries.

1. Project Setup

We begin by setting up a Maven project with Hibernate as the ORM provider and H2 as the in-memory database.

        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>7.1.1.Final</version>
            <type>pom</type>
        </dependency>
        
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.3.232</version>
            <scope>runtime</scope>
        </dependency>

Entity Class

We create an entity class Employee that will be stored in the database.

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private double salary;

    public Employee() {
    }

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" + "id=" + id + ", name=" + name + ", salary=" + salary + '}';
    }
    
}

This is a simple JPA entity with three fields: id, name, and salary. Hibernate automatically maps it to a table.

Utility Class for SessionFactory

Since both Session and StatelessSession require a SessionFactory, we create a helper utility class to initialize and provide access to it.

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernatePU");
            return emf.unwrap(SessionFactory.class);
        } catch (Exception ex) {
            throw new ExceptionInInitializerError("SessionFactory build failed: " + ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        getSessionFactory().close();
    }

}

This utility class loads the persistence unit defined in persistence.xml and unwraps the SessionFactory from it. The getSessionFactory() method is used throughout the application to obtain sessions.

2. Using StatelessSession

To understand the practical use of StatelessSession, below is an example code where we insert multiple Employee entities and then fetch them from the database. Unlike a regular session, Hibernate does not manage the entity state after insertion; therefore, no dirty checking or automatic updates occur later. Since we are using StatelessSession, objects are always fetched directly from the database without going through a persistence context or cache.

public class StatelessSessionExample {

    public static void main(String[] args) {
        StatelessSession session = HibernateUtil.getSessionFactory().openStatelessSession();
        Transaction tx = session.beginTransaction();

        // Batch Insert
        for (int i = 1; i <= 5; i++) {
            Employee emp = new Employee("Employee " + i, 3000 + i * 100);
            session.insert(emp);
        }

        tx.commit();

        // Querying with StatelessSession
        List<Employee> employees = session.createQuery("from Employee", Employee.class).list();
        employees.forEach(e ->
                System.out.println(e.getId() + " - " + e.getName() + " - " + e.getSalary()));

        session.close();
        HibernateUtil.shutdown();
    }
}

Sample Console Output

When running the above program with hibernate.show_sql=true, the output looks like this:

Hibernate: create table Employee (salary float(53) not null, id bigint generated by default as identity, name varchar(255), primary key (id))
Hibernate: insert into Employee (name,salary,id) values (?,?,default)
Hibernate: insert into Employee (name,salary,id) values (?,?,default)
Hibernate: insert into Employee (name,salary,id) values (?,?,default)
Hibernate: insert into Employee (name,salary,id) values (?,?,default)
Hibernate: insert into Employee (name,salary,id) values (?,?,default)
Hibernate: select e1_0.id,e1_0.name,e1_0.salary from Employee e1_0
1 - Employee 1 - 3100.0
2 - Employee 2 - 3200.0
3 - Employee 3 - 3300.0
4 - Employee 4 - 3400.0
5 - Employee 5 - 3500.0
Hibernate: drop table if exists Employee cascade

The first line shows Hibernate creating the Employee table based on the entity definition. It contains id as the primary key, name as a string field, and salary as a numeric field.

The next five lines correspond to direct INSERT statements generated by Hibernate for each employee object. Unlike a regular session, Hibernate does not manage entity state after insertion, so no dirty checking or automatic updates happen later. Each operation is immediately executed against the database without persisting objects in memory.

The SELECT statement retrieves all employees from the database. Since we are using StatelessSession, the objects are fetched directly from the database without going through a persistence context or cache. The printed results confirm that all five employees were successfully inserted with incremental IDs and salaries.

3. Benefits of Using StatelessSession

  • Efficient Batch Inserts: Every insert is executed directly, with no entity state tracking or cache maintenance. This makes batch operations significantly faster and more memory-efficient than using a regular session.
  • Predictable SQL Execution: Because there is no persistence context, each call maps directly to a SQL operation. This eliminates surprises with deferred flushing or automatic synchronization.
  • Lightweight Processing: Since Hibernate does not perform dirty checking or maintain first-level caching, memory usage is minimal, and performance is optimized for large-scale operations.
  • Best for Read-Only or Bulk Workloads: Objects retrieved are always fresh from the database, bypassing caches. This makes StatelessSession especially effective for reporting queries, ETL pipelines, or migration scripts where entities don’t need to be tracked after being read or inserted.

4. Conclusion

In this article, we explored how to use the Hibernate StatelessSession API as an alternative to the regular Session when working with performance-intensive operations. We created a utility class for managing the SessionFactory, and demonstrated how to insert and retrieve Employee entities. By reviewing the console output, we saw how every operation translates directly into SQL without the overhead of first-level caching, dirty checking, or entity state management.

The key takeaway is that StatelessSession is a lightweight and efficient option for batch processing, ETL jobs, reporting, and read-only operations where the convenience of a fully managed session is unnecessary. By using it appropriately, we can achieve significant performance gains while keeping memory usage low.

5. Download the Source Code

This article explored the Hibernate Stateless Session.

Download
You can download the full source code of this example here: hibernate stateless session

Omozegie Aziegbe

Omos Aziegbe is a technical writer and web/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button