HHH-9993 IsolationDelegate: add method to execute code without obtaining a connection

This commit is contained in:
Radim Vansa 2015-07-28 18:22:11 +02:00 committed by Steve Ebersole
parent 2167b442a4
commit aaf13cd123
3 changed files with 88 additions and 14 deletions

View File

@ -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> T delegateWork(WorkExecutorVisitable<T> 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> T delegateCallable(Callable<T> callable, boolean transacted) throws HibernateException;
}

View File

@ -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> T delegateCallable(Callable<T> 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);
}
}
}

View File

@ -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> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) throws HibernateException {
public <T> T delegateWork(final WorkExecutorVisitable<T> work, final boolean transacted) throws HibernateException {
return doInSuspendedTransaction(new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
HibernateCallable<T> workCallable = new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
return doTheWork(work);
}
};
if ( transacted ) {
return doInNewTransaction( workCallable, transactionManager );
}
else {
return workCallable.call();
}
}
});
}
@Override
public <T> T delegateCallable(final Callable<T> callable, final boolean transacted) throws HibernateException {
return doInSuspendedTransaction(new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
HibernateCallable<T> workCallable = new HibernateCallable<T>() {
@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> T doInSuspendedTransaction(HibernateCallable<T> 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> T doTheWorkInNewTransaction(WorkExecutorVisitable<T> work, TransactionManager transactionManager) {
private <T> T doInNewTransaction(HibernateCallable<T> 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> T doTheWorkInNoTransaction(WorkExecutorVisitable<T> work) {
return doTheWork( work );
}
private <T> T doTheWork(WorkExecutorVisitable<T> 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> {
T call() throws HibernateException;
}
}