Interface Session

All Superinterfaces:
AutoCloseable, EntityHandler, EntityManager, Serializable, SharedSessionContract
All Known Subinterfaces:
EventSource, SessionImplementor
All Known Implementing Classes:
SessionDelegatorBaseImpl, SessionLazyDelegator

public interface Session extends SharedSessionContract, EntityManager

The main runtime interface between a Java application and Hibernate. Represents the notion of a persistence context, a set of managed entity instances associated with a logical transaction.

The lifecycle of a Session is bounded by the beginning and end of the logical transaction. But a long logical transaction might span several database transactions.

The primary purpose of the Session is to offer create, read, and delete operations for instances of mapped entity classes. An instance may be in one of three states with respect to a given open session:

  • transient: never persistent, and not associated with the Session,
  • persistent: currently associated with the Session, or
  • detached: previously persistent, but not currently associated with the Session.

Each persistent instance has a persistent identity determined by its type and identifier value. There may be at most one persistent instance with a given persistent identity associated with a given session. A persistent identity is assigned when an instance is made persistent.

An instance of an entity class may be associated with at most one open session. Distinct sessions represent state with the same persistent identity using distinct persistent instances of the mapped entity class.

Any instance returned by EntityHandler.get(Class,Object), find(Class,Object), or by a query is persistent. A persistent instance might hold references to other entity instances, and sometimes these references are proxied by an intermediate object. When an associated entity has not yet been fetched from the database, references to the unfetched entity are represented by uninitialized proxies. The state of an unfetched entity is automatically fetched from the database when a method of its proxy is invoked, if and only if the proxy is associated with an open session. Otherwise, getReference(Object) may be used to trade a proxy belonging to a closed session for a new proxy associated with the current session.

A transient instance may be made persistent by calling persist(Object). A persistent instance may be made detached by calling detach(Object). A persistent instance may be marked for removal, and eventually made transient, by calling remove(Object).

Persistent instances are held in a managed state by the persistence context. Any change to the state of a persistent instance is automatically detected and eventually flushed to the database. This process of automatic change detection is called dirty checking and can be expensive in some circumstances. Dirty checking may be disabled by marking an entity as read-only using setReadOnly(Object,boolean) or simply by evicting it from the persistence context. A session may be set to load entities as read-only by default, or this may be controlled at the query level.

The state of a transient or detached instance may be made persistent by copying it to a persistent instance using merge(Object). Since version 7, all older operations which moved a detached instance to the persistent state have been completely removed, and clients must now migrate to the use of merge().

The persistent state of a managed entity may be refreshed from the database, discarding all modifications to the object held in memory, by calling refresh(Object).

From time to time, a flush operation is triggered, and the session synchronizes state held in memory with persistent state held in the database by executing SQL insert, update, and delete statements. Note that SQL statements are often not executed synchronously by the methods of the Session interface. If synchronous execution of SQL is desired, the StatelessSession allows this.

Each managed instance has an associated LockMode. By default, the session obtains only LockMode.READ on an entity instance it reads from the database and LockMode.WRITE on an entity instance it writes to the database. This behavior is appropriate for programs which use optimistic locking.

A persistence context holds hard references to all its entities and prevents them from being garbage collected. Therefore, a Session is a short-lived object, and must be discarded as soon as a logical transaction ends. In extreme cases, clear() and detach(Object) may be used to control memory usage. However, for processes which read many entities, a StatelessSession should be used.

A session might be associated with a container-managed JTA transaction, or it might be in control of its own resource-local database transaction. In the case of a resource-local transaction, the client must demarcate the beginning and end of the transaction using a Transaction. A typical resource-local transaction should use the following idiom:

try (var session = factory.openSession()) {
	Transaction tx = null;
	try {
    	tx = session.beginTransaction();
		//do some work
    	...
    	tx.commit();
	}
	catch (Exception e) {
    	if (tx!=null) tx.rollback();
    	throw e;
	}
}

It's crucially important to appreciate the following restrictions and why they exist:

  • If the Session throws an exception, the current transaction must be rolled back and the session must be discarded. The internal state of the Session cannot be expected to be consistent with the database after the exception occurs.
  • At the end of a logical transaction, the session must be explicitly destroyed, so that all JDBC resources may be released.
  • If a transaction is rolled back, the state of the persistence context and of its associated entities must be assumed inconsistent with the database, and the session must be discarded.
  • A Session is never thread-safe. It contains various different sorts of fragile mutable state. Each thread or transaction must obtain its own dedicated instance from the SessionFactory.

An easy way to be sure that session and transaction management is being done correctly is to let the factory do it:

sessionFactory.inTransaction(session -> {
    //do the work
    ...
});

A session may be used to execute JDBC work using its JDBC connection and transaction:

session.doWork(connection -> {
	try (var statement = connection.prepareStatement(...)) {
		statement.execute();
	}
});

A Session instance is serializable if its entities are serializable.

Every Session is a JPA EntityManager. Furthermore, when Hibernate is acting as the JPA persistence provider, the method EntityHandler.unwrap(Class) may be used to obtain the underlying Session.

Hibernate, unlike JPA, allows a persistence unit where an entity class is mapped multiple times, with different entity names, usually to different tables. In this case, the session needs a way to identify the entity name of a given instance of the entity class. Therefore, some operations of this interface, including operations inherited from EntityManager, are overloaded with a form that accepts an explicit entity name along with the instance. An alternative solution to this problem is to provide an EntityNameResolver.

See Also: