- * That is returning successfully or via a caught exception. - * Unexpected exceptions are caught via the Thread uncaughtExceptionHandler. - *
- * - * @param returnOrThrowable the return or throwable object - * @param opCode the opcode for ATHROW or ARETURN etc - * @param scopeTrans the scoped transaction the method was run with. + * Exiting an enhanced transactional method. */ - public static void onExitScopeTrans(Object returnOrThrowable, int opCode, ScopeTrans scopeTrans) { + public static void exit(Object returnOrThrowable, int opCode) { + server().scopedTransactionExit(returnOrThrowable, opCode); + } - scopeTrans.onExit(returnOrThrowable, opCode); + private static SpiEbeanServer server() { + return (SpiEbeanServer) Ebean.getDefaultServer(); } } diff --git a/src/main/java/io/ebeaninternal/api/ScopeTrans.java b/src/main/java/io/ebeaninternal/api/ScopeTrans.java index 0cd93d702..641a8c639 100644 --- a/src/main/java/io/ebeaninternal/api/ScopeTrans.java +++ b/src/main/java/io/ebeaninternal/api/ScopeTrans.java @@ -8,17 +8,10 @@ import java.util.ArrayList; /** * Used internally to handle the scoping of transactions for methods. */ -public class ScopeTrans implements Thread.UncaughtExceptionHandler { +public class ScopeTrans { private static final int OPCODE_ATHROW = 191; - private final SpiTransactionScopeManager scopeMgr; - - /** - * The suspended transaction (can be null). - */ - private final SpiTransaction suspendedTransaction; - /** * The transaction in scope (can be null). */ @@ -61,15 +54,11 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler { private boolean rolledBack; - public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope, - SpiTransaction suspendedTransaction, SpiTransactionScopeManager scopeMgr) { + public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope) { this.rollbackOnChecked = rollbackOnChecked; this.created = created; this.transaction = transaction; - this.suspendedTransaction = suspendedTransaction; - this.scopeMgr = scopeMgr; - this.noRollbackFor = txScope.getNoRollbackFor(); this.rollbackFor = txScope.getRollbackFor(); @@ -108,55 +97,30 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler { } /** - * Called when the Thread catches any uncaught exception. - * For example, an unexpected NullPointerException or Error. + * Complete the transaction from enhanced transactional. Try to commit. */ - @Override - public void uncaughtException(Thread thread, Throwable e) { - - // rollback transaction if required - caughtThrowable(e); - - // reinstate suspended transaction - onFinally(); - } - - /** - * Returned via RETURN or expected Exception from the method. - * - * @param returnOrThrowable the return value or Throwable - * @param opCode indicates - */ - public void onExit(Object returnOrThrowable, int opCode) { + void complete(Object returnOrThrowable, int opCode) { if (opCode == OPCODE_ATHROW) { // exited with a Throwable caughtThrowable((Throwable) returnOrThrowable); } - onFinally(); + complete(); } /** - * Commit if the transaction exists and has not already been rolled back. - * Also reinstate the suspended transaction if there was one. + * Complete the transaction programmatically. Try to commit. */ - public void onFinally() { - - try { - if (!rolledBack) { - commitTransaction(); - } - } finally { - restoreSuspended(); + public void complete() { + if (!rolledBack) { + commitTransaction(); } } - protected void restoreSuspended() { - if (created || suspendedTransaction != null) { - // put the previously suspended transaction - // back onto the ThreadLocal or equivalent - scopeMgr.replace(suspendedTransaction); + public void end() { + if (created) { + transaction.end(); } } @@ -247,17 +211,10 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler { } } - - if (e instanceof RuntimeException) { - return true; - - } else { - // checked exceptions... - // EJB defaults this to false which is not intuitive IMO - // Ebean makes this configurable (default to true) - return rollbackOnChecked; - } + // checked exceptions... + // EJB defaults this to false which is not intuitive IMO + // Ebean makes this configurable (default to true) + return e instanceof RuntimeException || rollbackOnChecked; } - } diff --git a/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index a4028904f..337f12595 100644 --- a/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -1,432 +1,116 @@ package io.ebeaninternal.api; -import io.ebean.annotation.PersistBatch; -import io.ebean.TransactionCallback; -import io.ebean.annotation.DocStoreMode; -import io.ebean.bean.PersistenceContext; -import io.ebean.event.changelog.BeanChange; -import io.ebean.event.changelog.ChangeSet; -import io.ebeaninternal.server.core.PersistDeferredRelationship; -import io.ebeaninternal.server.core.PersistRequest; -import io.ebeaninternal.server.core.PersistRequestBean; -import io.ebeaninternal.server.persist.BatchControl; -import io.ebeaninternal.server.transaction.ProfileStream; -import io.ebeanservice.docstore.api.DocStoreTransaction; +import io.ebeaninternal.server.transaction.TransactionScopeManager; +import io.ebeaninternal.server.util.ArrayStack; import javax.persistence.PersistenceException; -import java.sql.Connection; -import java.sql.SQLException; /** - * Wrapper of a ScopeTrans request and it's underlying transaction. + * Manage scoped (typically thread local) transactions. + * + * These can be nested and internally they are pushed and popped from a stack. */ -public class ScopedTransaction implements SpiTransaction { +public class ScopedTransaction extends SpiTransactionProxy { - private final ScopeTrans scopeTrans; + private final TransactionScopeManager manager; - private final SpiTransaction transaction; + /** + * Stack of 'nested' transactions. + */ + private ArrayStack P executeInTrans(Function P executeInTrans(Function