Skip to content

Commit aaf13cd

Browse files
rvansasebersole
authored andcommitted
HHH-9993 IsolationDelegate: add method to execute code without obtaining a connection
1 parent 2167b44 commit aaf13cd

File tree

3 files changed

+88
-14
lines changed

3 files changed

+88
-14
lines changed

hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.hibernate.HibernateException;
1010
import org.hibernate.jdbc.WorkExecutorVisitable;
1111

12+
import java.util.concurrent.Callable;
13+
1214
/**
1315
* Contract for performing work in a manner that isolates it from any current transaction.
1416
*
@@ -26,4 +28,16 @@ public interface IsolationDelegate {
2628
* @throws HibernateException Indicates a problem performing the work.
2729
*/
2830
public <T> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) throws HibernateException;
31+
32+
/**
33+
* Invoke the given callable in isolation from current transaction.
34+
*
35+
* @param callable The callable to be invoked.
36+
* @param transacted Should the work itself be done in a (isolated) transaction?
37+
*
38+
* @return The work result
39+
*
40+
* @throws HibernateException Indicates a problem performing the work.
41+
*/
42+
public <T> T delegateCallable(Callable<T> callable, boolean transacted) throws HibernateException;
2943
}

hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcIsolationDelegate.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.sql.Connection;
1010
import java.sql.SQLException;
11+
import java.util.concurrent.Callable;
1112

1213
import org.hibernate.HibernateException;
1314
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
@@ -102,4 +103,18 @@ else if ( e instanceof SQLException ) {
102103
throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
103104
}
104105
}
106+
107+
@Override
108+
public <T> T delegateCallable(Callable<T> callable, boolean transacted) throws HibernateException {
109+
// No connection, nothing to be suspended
110+
try {
111+
return callable.call();
112+
}
113+
catch (HibernateException e) {
114+
throw e;
115+
}
116+
catch (Exception e) {
117+
throw new HibernateException(e);
118+
}
119+
}
105120
}

hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaIsolationDelegate.java

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import javax.transaction.TransactionManager;
1313
import java.sql.Connection;
1414
import java.sql.SQLException;
15+
import java.util.concurrent.Callable;
1516

1617
import org.hibernate.HibernateException;
1718
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
@@ -52,21 +53,64 @@ protected SqlExceptionHelper sqlExceptionHelper() {
5253
}
5354

5455
@Override
55-
public <T> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) throws HibernateException {
56+
public <T> T delegateWork(final WorkExecutorVisitable<T> work, final boolean transacted) throws HibernateException {
57+
return doInSuspendedTransaction(new HibernateCallable<T>() {
58+
@Override
59+
public T call() throws HibernateException {
60+
HibernateCallable<T> workCallable = new HibernateCallable<T>() {
61+
@Override
62+
public T call() throws HibernateException {
63+
return doTheWork(work);
64+
}
65+
};
66+
if ( transacted ) {
67+
return doInNewTransaction( workCallable, transactionManager );
68+
}
69+
else {
70+
return workCallable.call();
71+
}
72+
}
73+
});
74+
}
75+
76+
@Override
77+
public <T> T delegateCallable(final Callable<T> callable, final boolean transacted) throws HibernateException {
78+
return doInSuspendedTransaction(new HibernateCallable<T>() {
79+
@Override
80+
public T call() throws HibernateException {
81+
HibernateCallable<T> workCallable = new HibernateCallable<T>() {
82+
@Override
83+
public T call() throws HibernateException {
84+
try {
85+
return callable.call();
86+
}
87+
catch (HibernateException e) {
88+
throw e;
89+
}
90+
catch (Exception e) {
91+
throw new HibernateException(e);
92+
}
93+
}
94+
};
95+
if ( transacted ) {
96+
return doInNewTransaction( workCallable, transactionManager );
97+
}
98+
else {
99+
return workCallable.call();
100+
}
101+
}
102+
});
103+
}
104+
105+
private <T> T doInSuspendedTransaction(HibernateCallable<T> callable) {
56106
try {
57107
// First we suspend any current JTA transaction
58108
Transaction surroundingTransaction = transactionManager.suspend();
59109
LOG.debugf( "Surrounding JTA transaction suspended [%s]", surroundingTransaction );
60110

61111
boolean hadProblems = false;
62112
try {
63-
// then perform the requested work
64-
if ( transacted ) {
65-
return doTheWorkInNewTransaction( work, transactionManager );
66-
}
67-
else {
68-
return doTheWorkInNoTransaction( work );
69-
}
113+
return callable.call();
70114
}
71115
catch (HibernateException e) {
72116
hadProblems = true;
@@ -91,13 +135,13 @@ public <T> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) thr
91135
}
92136
}
93137

94-
private <T> T doTheWorkInNewTransaction(WorkExecutorVisitable<T> work, TransactionManager transactionManager) {
138+
private <T> T doInNewTransaction(HibernateCallable<T> callable, TransactionManager transactionManager) {
95139
try {
96140
// start the new isolated transaction
97141
transactionManager.begin();
98142

99143
try {
100-
T result = doTheWork( work );
144+
T result = callable.call();
101145
// if everything went ok, commit the isolated transaction
102146
transactionManager.commit();
103147
return result;
@@ -120,10 +164,6 @@ private <T> T doTheWorkInNewTransaction(WorkExecutorVisitable<T> work, Transacti
120164
}
121165
}
122166

123-
private <T> T doTheWorkInNoTransaction(WorkExecutorVisitable<T> work) {
124-
return doTheWork( work );
125-
}
126-
127167
private <T> T doTheWork(WorkExecutorVisitable<T> work) {
128168
try {
129169
// obtain our isolated connection
@@ -152,4 +192,9 @@ private <T> T doTheWork(WorkExecutorVisitable<T> work) {
152192
throw sqlExceptionHelper().convert( e, "unable to obtain isolated JDBC connection" );
153193
}
154194
}
195+
196+
// Callable that does not throw Exception; in Java <8 there's no Supplier
197+
private interface HibernateCallable<T> {
198+
T call() throws HibernateException;
199+
}
155200
}

0 commit comments

Comments
 (0)