HHH-16637 add methods to SessionFactory for handling lifecycle of StatelessSession

also clean up the related code
This commit is contained in:
Gavin 2023-05-19 08:38:16 +02:00 committed by Gavin King
parent e4b31c192e
commit eafe6fd79b
3 changed files with 128 additions and 65 deletions

View File

@ -24,6 +24,8 @@ import org.hibernate.stat.Statistics;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManagerFactory;
import static org.hibernate.internal.TransactionManagement.manageTransaction;
/**
* A {@code SessionFactory} represents an "instance" of Hibernate: it maintains
* the runtime metamodel representing persistent entities, their attributes,
@ -193,7 +195,16 @@ public interface SessionFactory extends EntityManagerFactory, Referenceable, Ser
* Open a {@link Session} and use it to perform an action.
*/
default void inSession(Consumer<Session> action) {
try (Session session = openSession()) {
try ( Session session = openSession() ) {
action.accept( session );
}
}
/**
* Open a {@link StatelessSession} and use it to perform an action.
*/
default void inStatelessSession(Consumer<StatelessSession> action) {
try ( StatelessSession session = openStatelessSession() ) {
action.accept( session );
}
}
@ -203,86 +214,49 @@ public interface SessionFactory extends EntityManagerFactory, Referenceable, Ser
* within the bounds of a transaction.
*/
default void inTransaction(Consumer<Session> action) {
inSession(
session -> {
final Transaction transaction = session.beginTransaction();
try {
action.accept( session );
if ( !transaction.isActive() ) {
throw new TransactionManagementException(
"Execution of action caused managed transaction to be completed" );
}
}
catch (RuntimeException exception) {
// an error happened in the action
if ( transaction.isActive() ) {
try {
transaction.rollback();
}
catch (Exception ignore) {
}
}
throw exception;
}
// The action completed without throwing an exception,
// so we attempt to commit the transaction, allowing
// any RollbackException to propagate. Note that when
// we get here we know that the transaction is active
transaction.commit();
}
);
inSession( session -> manageTransaction( session, session.beginTransaction(), action ) );
}
class TransactionManagementException extends RuntimeException {
TransactionManagementException(String message) {
super( message );
}
/**
* Open a {@link StatelessSession} and use it to perform an action
* within the bounds of a transaction.
*/
default void inStatelessTransaction(Consumer<StatelessSession> action) {
inStatelessSession( session -> manageTransaction( session, session.beginTransaction(), action ) );
}
/**
* Open a {@link Session} and use it to obtain a value.
*/
default <R> R fromSession(Function<Session,R> action) {
try (Session session = openSession()) {
try ( Session session = openSession() ) {
return action.apply( session );
}
}
/**
* Open a {@link Session} and use it to perform an action
* Open a {@link StatelessSession} and use it to obtain a value.
*/
default <R> R fromStatelessSession(Function<StatelessSession,R> action) {
try ( StatelessSession session = openStatelessSession() ) {
return action.apply( session );
}
}
/**
* Open a {@link Session} and use it to obtain a value
* within the bounds of a transaction.
*/
default <R> R fromTransaction(Function<Session,R> action) {
return fromSession(
session -> {
final Transaction transaction = session.beginTransaction();
try {
R result = action.apply( session );
if ( !transaction.isActive() ) {
throw new TransactionManagementException(
"Execution of action caused managed transaction to be completed" );
}
// The action completed without throwing an exception,
// so we attempt to commit the transaction, allowing
// any RollbackException to propagate. Note that when
// we get here we know that the transaction is active
transaction.commit();
return result;
}
catch (RuntimeException exception) {
// an error happened in the action or during commit()
if ( transaction.isActive() ) {
try {
transaction.rollback();
}
catch (Exception ignore) {
}
}
throw exception;
}
}
);
return fromSession( session -> manageTransaction( session, session.beginTransaction(), action ) );
}
/**
* Open a {@link StatelessSession} and use it to obtain a value
* within the bounds of a transaction.
*/
default <R> R fromStatelessTransaction(Function<StatelessSession,R> action) {
return fromStatelessSession( session -> manageTransaction( session, session.beginTransaction(), action ) );
}
/**

View File

@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate;
/**
* Thrown when user code causes the end of a transaction that is
* being managed by the {@link SessionFactory}.
*
* @see SessionFactory#inTransaction
* @see SessionFactory#fromTransaction
*/
public class TransactionManagementException extends RuntimeException {
public TransactionManagementException(String message) {
super( message );
}
}

View File

@ -0,0 +1,68 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.internal;
import org.hibernate.Transaction;
import org.hibernate.TransactionManagementException;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Methods used by {@link org.hibernate.SessionFactory} to manage transactions.
*/
public class TransactionManagement {
public static <S> void manageTransaction(S session, Transaction transaction, Consumer<S> consumer) {
try {
consumer.accept( session );
commit( transaction );
}
catch ( RuntimeException exception ) {
rollback( transaction, exception );
throw exception;
}
}
public static <S,R> R manageTransaction(S session, Transaction transaction, Function<S,R> function) {
try {
R result = function.apply( session );
commit( transaction );
return result;
}
catch ( RuntimeException exception ) {
// an error happened in the action or during commit()
rollback( transaction, exception );
throw exception;
}
}
private static void rollback(Transaction transaction, RuntimeException exception) {
// an error happened in the action or during commit()
if ( transaction.isActive() ) {
try {
transaction.rollback();
}
catch ( RuntimeException e ) {
exception.addSuppressed( e );
}
}
}
private static void commit(Transaction transaction) {
if ( !transaction.isActive() ) {
throw new TransactionManagementException(
"Execution of action caused managed transaction to be completed" );
}
// The action completed without throwing an exception,
// so we attempt to commit the transaction, allowing
// any RollbackException to propagate. Note that when
// we get here we know that the transaction is active
transaction.commit();
}
}