HHH-9993 IsolationDelegate: add method to execute code without obtaining a connection
This commit is contained in:
parent
2167b442a4
commit
aaf13cd123
|
@ -9,6 +9,8 @@ package org.hibernate.engine.transaction.spi;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.jdbc.WorkExecutorVisitable;
|
import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for performing work in a manner that isolates it from any current transaction.
|
* 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.
|
* @throws HibernateException Indicates a problem performing the work.
|
||||||
*/
|
*/
|
||||||
public <T> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) throws HibernateException;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.resource.transaction.backend.jdbc.internal;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
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" );
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import javax.transaction.Transaction;
|
||||||
import javax.transaction.TransactionManager;
|
import javax.transaction.TransactionManager;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||||
|
@ -52,7 +53,56 @@ public class JtaIsolationDelegate implements IsolationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
try {
|
||||||
// First we suspend any current JTA transaction
|
// First we suspend any current JTA transaction
|
||||||
Transaction surroundingTransaction = transactionManager.suspend();
|
Transaction surroundingTransaction = transactionManager.suspend();
|
||||||
|
@ -60,13 +110,7 @@ public class JtaIsolationDelegate implements IsolationDelegate {
|
||||||
|
|
||||||
boolean hadProblems = false;
|
boolean hadProblems = false;
|
||||||
try {
|
try {
|
||||||
// then perform the requested work
|
return callable.call();
|
||||||
if ( transacted ) {
|
|
||||||
return doTheWorkInNewTransaction( work, transactionManager );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return doTheWorkInNoTransaction( work );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (HibernateException e) {
|
catch (HibernateException e) {
|
||||||
hadProblems = true;
|
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 {
|
try {
|
||||||
// start the new isolated transaction
|
// start the new isolated transaction
|
||||||
transactionManager.begin();
|
transactionManager.begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
T result = doTheWork( work );
|
T result = callable.call();
|
||||||
// if everything went ok, commit the isolated transaction
|
// if everything went ok, commit the isolated transaction
|
||||||
transactionManager.commit();
|
transactionManager.commit();
|
||||||
return result;
|
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) {
|
private <T> T doTheWork(WorkExecutorVisitable<T> work) {
|
||||||
try {
|
try {
|
||||||
// obtain our isolated connection
|
// obtain our isolated connection
|
||||||
|
@ -152,4 +192,9 @@ public class JtaIsolationDelegate implements IsolationDelegate {
|
||||||
throw sqlExceptionHelper().convert( e, "unable to obtain isolated JDBC connection" );
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue