From aaf13cd123fed545b30b33c8bf57e07c5bf3e8dc Mon Sep 17 00:00:00 2001 From: Radim Vansa Date: Tue, 28 Jul 2015 18:22:11 +0200 Subject: [PATCH] HHH-9993 IsolationDelegate: add method to execute code without obtaining a connection --- .../transaction/spi/IsolationDelegate.java | 14 ++++ .../jdbc/internal/JdbcIsolationDelegate.java | 15 ++++ .../jta/internal/JtaIsolationDelegate.java | 73 +++++++++++++++---- 3 files changed, 88 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java b/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java index a88a814eca..9308b24fc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java @@ -9,6 +9,8 @@ package org.hibernate.engine.transaction.spi; import org.hibernate.HibernateException; import org.hibernate.jdbc.WorkExecutorVisitable; +import java.util.concurrent.Callable; + /** * Contract for performing work in a manner that isolates it from any current transaction. * @@ -26,4 +28,16 @@ public interface IsolationDelegate { * @throws HibernateException Indicates a problem performing the work. */ public T delegateWork(WorkExecutorVisitable work, boolean transacted) throws HibernateException; + + /** + * Invoke the given callable in isolation from current transaction. + * + * @param callable The callable to be invoked. + * @param transacted Should the work itself be done in a (isolated) transaction? + * + * @return The work result + * + * @throws HibernateException Indicates a problem performing the work. + */ + public T delegateCallable(Callable callable, boolean transacted) throws HibernateException; } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcIsolationDelegate.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcIsolationDelegate.java index 4ec6bd4ba6..3268365f54 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcIsolationDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcIsolationDelegate.java @@ -8,6 +8,7 @@ package org.hibernate.resource.transaction.backend.jdbc.internal; import java.sql.Connection; import java.sql.SQLException; +import java.util.concurrent.Callable; import org.hibernate.HibernateException; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -102,4 +103,18 @@ public class JdbcIsolationDelegate implements IsolationDelegate { throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" ); } } + + @Override + public T delegateCallable(Callable callable, boolean transacted) throws HibernateException { + // No connection, nothing to be suspended + try { + return callable.call(); + } + catch (HibernateException e) { + throw e; + } + catch (Exception e) { + throw new HibernateException(e); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaIsolationDelegate.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaIsolationDelegate.java index 3ca39329b2..2789e1d294 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaIsolationDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaIsolationDelegate.java @@ -12,6 +12,7 @@ import javax.transaction.Transaction; import javax.transaction.TransactionManager; import java.sql.Connection; import java.sql.SQLException; +import java.util.concurrent.Callable; import org.hibernate.HibernateException; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -52,7 +53,56 @@ public class JtaIsolationDelegate implements IsolationDelegate { } @Override - public T delegateWork(WorkExecutorVisitable work, boolean transacted) throws HibernateException { + public T delegateWork(final WorkExecutorVisitable work, final boolean transacted) throws HibernateException { + return doInSuspendedTransaction(new HibernateCallable() { + @Override + public T call() throws HibernateException { + HibernateCallable workCallable = new HibernateCallable() { + @Override + public T call() throws HibernateException { + return doTheWork(work); + } + }; + if ( transacted ) { + return doInNewTransaction( workCallable, transactionManager ); + } + else { + return workCallable.call(); + } + } + }); + } + + @Override + public T delegateCallable(final Callable callable, final boolean transacted) throws HibernateException { + return doInSuspendedTransaction(new HibernateCallable() { + @Override + public T call() throws HibernateException { + HibernateCallable workCallable = new HibernateCallable() { + @Override + public T call() throws HibernateException { + try { + return callable.call(); + } + catch (HibernateException e) { + throw e; + } + catch (Exception e) { + throw new HibernateException(e); + } + } + }; + if ( transacted ) { + return doInNewTransaction( workCallable, transactionManager ); + } + else { + return workCallable.call(); + } + } + }); + } + + private T doInSuspendedTransaction(HibernateCallable callable) { try { // First we suspend any current JTA transaction Transaction surroundingTransaction = transactionManager.suspend(); @@ -60,13 +110,7 @@ public class JtaIsolationDelegate implements IsolationDelegate { boolean hadProblems = false; try { - // then perform the requested work - if ( transacted ) { - return doTheWorkInNewTransaction( work, transactionManager ); - } - else { - return doTheWorkInNoTransaction( work ); - } + return callable.call(); } catch (HibernateException e) { hadProblems = true; @@ -91,13 +135,13 @@ public class JtaIsolationDelegate implements IsolationDelegate { } } - private T doTheWorkInNewTransaction(WorkExecutorVisitable work, TransactionManager transactionManager) { + private T doInNewTransaction(HibernateCallable callable, TransactionManager transactionManager) { try { // start the new isolated transaction transactionManager.begin(); try { - T result = doTheWork( work ); + T result = callable.call(); // if everything went ok, commit the isolated transaction transactionManager.commit(); return result; @@ -120,10 +164,6 @@ public class JtaIsolationDelegate implements IsolationDelegate { } } - private T doTheWorkInNoTransaction(WorkExecutorVisitable work) { - return doTheWork( work ); - } - private T doTheWork(WorkExecutorVisitable work) { try { // obtain our isolated connection @@ -152,4 +192,9 @@ public class JtaIsolationDelegate implements IsolationDelegate { throw sqlExceptionHelper().convert( e, "unable to obtain isolated JDBC connection" ); } } + + // Callable that does not throw Exception; in Java <8 there's no Supplier + private interface HibernateCallable { + T call() throws HibernateException; + } }