All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.narayana.jta.QuarkusTransaction Maven / Gradle / Ivy

There is a newer version: 3.17.0
Show newest version
package io.quarkus.narayana.jta;

import java.util.concurrent.Callable;
import java.util.function.Function;

import jakarta.transaction.Status;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transactional;

import com.arjuna.ats.jta.UserTransaction;

/**
 * A simplified transaction interface. While broadly covering the same use cases as {@link jakarta.transaction.UserTransaction},
 * this class is designed to be easier to use. The main features it offers over {@code UserTransaction} are:
 *
 * 
    *
  • No Checked Exceptions: All underlying checked exceptions are wrapped in an unchecked * {@link QuarkusTransactionException}.
  • *
  • No Transaction Leaks: Transactions are tied to the request scope, if the scope is destroyed before the transaction * is committed the transaction is rolled back. Note that this means this can only currently be used when the request scope is * active.
  • *
  • Per Transaction Timeouts: * {{@link BeginOptions#timeout(int)}/{@link TransactionRunnerOptions#timeout(int)} * can be used to set the new transactions timeout, without affecting the per thread default.
  • *
  • Lambda Style Transactions: {@link Runnable} and {@link Callable} instances can be run inside the scope of a new * transaction.
  • *
*

* Note that any checked exception will be wrapped by a {@link QuarkusTransactionException}, while unchecked exceptions are * allowed to propagate unchanged. */ public interface QuarkusTransaction { /** * Starts a transaction, using the system default timeout. *

* This transaction will be tied to the current request scope, if it is not committed when the scope is destroyed then it * will be rolled back to prevent transaction leaks. */ static void begin() { begin(beginOptions()); } /** * Starts a transaction, using the system default timeout. *

* This transaction will be tied to the current request scope, if it is not committed when the scope is destroyed then it * will be rolled back to prevent transaction leaks. * * @param options Options that apply to the new transaction */ static void begin(BeginOptions options) { QuarkusTransactionImpl.begin(options); } /** * Commits the current transaction. */ static void commit() { QuarkusTransactionImpl.commit(); } /** * Rolls back the current transaction. */ static void rollback() { QuarkusTransactionImpl.rollback(); } /** * If a transaction is active. * * @return {@code true} if the transaction is active. */ static boolean isActive() { try { return UserTransaction.userTransaction().getStatus() != Status.STATUS_NO_TRANSACTION; } catch (SystemException e) { throw new QuarkusTransactionException(e); } } /** * If the transaction is rollback only * * @return If the transaction has been marked for rollback */ static boolean isRollbackOnly() { try { return UserTransaction.userTransaction().getStatus() == Status.STATUS_MARKED_ROLLBACK; } catch (SystemException e) { throw new QuarkusTransactionException(e); } } /** * Marks the transaction as rollback only. Operations can still be carried out, however the transaction cannot be * successfully committed. */ static void setRollbackOnly() { QuarkusTransactionImpl.setRollbackOnly(); } /** * Starts the definition of a transaction runner, * which can then be used to run a task ({@link Runnable}, {@link Callable}, ...), * with {@link TransactionSemantics#JOIN_EXISTING} semantics: *

    *
  • If no transaction is active then a new transaction will be started, and committed when the method ends. *
  • If an exception is thrown the exception handler registered by * {@link TransactionRunnerOptions#exceptionHandler(Function)} will be called to * decide if the TX should be committed or rolled back. *
  • If an existing transaction is active then the method is run in the context of the existing transaction. If an * exception is thrown the exception handler will be called, however * a result of {@link TransactionExceptionResult#ROLLBACK} will result in the TX marked as rollback only, while a result of * {@link TransactionExceptionResult#COMMIT} will result in no action being taken. *
*

* Examples of use: * *

{@code
     * QuarkusTransaction.joiningExisting().run(() -> ...);
     * int value = QuarkusTransaction.joiningExisting().call(() -> { ...; return 42; });
     * }
* * @return An interface that allow various options of a transaction runner to be customized, * or a {@link Runnable}/{@link Callable} to be executed. * @see TransactionRunnerOptions */ static TransactionRunnerOptions joiningExisting() { return runner(TransactionSemantics.JOIN_EXISTING); } /** * Starts the definition of a transaction runner, * which can then be used to run a task ({@link Runnable}, {@link Callable}, ...), * with {@link TransactionSemantics#REQUIRE_NEW} semantics: *
    *
  • If an existing transaction is already associated with the current thread then the transaction is suspended, * then a new transaction is started which follows all the normal lifecycle rules, * and when it's complete the original transaction is resumed. *
  • Otherwise a new transaction is started, and follows all the normal lifecycle rules. *
*

* Examples of use: * *

{@code
     * QuarkusTransaction.requiringNew().run(() -> ...);
     * int value = QuarkusTransaction.requiringNew().call(() -> { ...; return 42; });
     * }
* * @return An interface that allow various options of a transaction runner to be customized, * or a {@link Runnable}/{@link Callable} to be executed. * @see TransactionRunnerOptions */ static TransactionRunnerOptions requiringNew() { return runner(TransactionSemantics.REQUIRE_NEW); } /** * Starts the definition of a transaction runner, * which can then be used to run a task ({@link Runnable}, {@link Callable}, ...), * with {@link TransactionSemantics#DISALLOW_EXISTING} semantics: *
    *
  • If a transaction is already associated with the current thread a {@link QuarkusTransactionException} will be thrown, *
  • Otherwise a new transaction is started, and follows all the normal lifecycle rules. *
*

* Examples of use: * *

{@code
     * QuarkusTransaction.requiringNew().run(() -> ...);
     * int value = QuarkusTransaction.requiringNew().call(() -> { ...; return 42; });
     * }
* * @return An interface that allow various options of a transaction runner to be customized, * or a {@link Runnable}/{@link Callable} to be executed. * @see TransactionRunnerOptions */ static TransactionRunnerOptions disallowingExisting() { return runner(TransactionSemantics.DISALLOW_EXISTING); } /** * Starts the definition of a transaction runner, * which can then be used to run a task ({@link Runnable}, {@link Callable}, ...), * with {@link TransactionSemantics#SUSPEND_EXISTING} semantics: *
    *
  • If no transaction is active then these semantics are basically a no-op. *
  • If a transaction is active then it is suspended, and resumed after the task is run. *
  • The exception handler will never be consulted when these semantics are in use, specifying both an exception handler * and * these semantics are considered an error. *
  • These semantics allows for code to easily be run outside the scope of a transaction. *
*

* Examples of use: * *

{@code
     * QuarkusTransaction.requiringNew().run(() -> ...);
     * int value = QuarkusTransaction.requiringNew().call(() -> { ...; return 42; });
     * }
* * @return An interface that allow various options of a transaction runner to be customized, * or a {@link Runnable}/{@link Callable} to be executed. * @see TransactionRunnerOptions */ static TransactionRunnerOptions suspendingExisting() { return runner(TransactionSemantics.SUSPEND_EXISTING); } /** * Starts the definition of a transaction runner, * which can then be used to run a task ({@link Runnable}, {@link Callable}, ...), * following the selected {@link TransactionSemantics}. *

* Examples of use: * *

{@code
     * QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).run(() -> ...);
     * QuarkusTransaction.runner(TransactionSemantics.JOIN_EXISTING).run(() -> ...);
     * QuarkusTransaction.runner(TransactionSemantics.SUSPEND_EXISTING).run(() -> ...);
     * QuarkusTransaction.runner(TransactionSemantics.DISALLOW_EXISTING).run(() -> ...);
     * int value = QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).call(() -> { ...; return 42; });
     * int value = QuarkusTransaction.runner(TransactionSemantics.JOIN_EXISTING).call(() -> { ...; return 42; });
     * int value = QuarkusTransaction.runner(TransactionSemantics.SUSPEND_EXISTING).call(() -> { ...; return 42; });
     * int value = QuarkusTransaction.runner(TransactionSemantics.DISALLOW_EXISTING).call(() -> { ...; return 42; });
     * }
* * @param semantics The selected {@link TransactionSemantics}. * @return An interface that allow various options of a transaction runner to be customized, * or a {@link Runnable}/{@link Callable} to be executed. * @see TransactionRunnerOptions */ static TransactionRunnerOptions runner(TransactionSemantics semantics) { return new TransactionRunnerImpl(semantics); } /** * Runs a task in a new transaction with the default timeout. This defaults to {@link Transactional.TxType#REQUIRES_NEW} * semantics, however alternate semantics can be requested using {@link #run(RunOptions, Runnable)}. * * @param task The task to run in a transaction * @deprecated For the same semantics, use {@link #requiringNew() QuarkusTransaction.requiringNew().run(task)}. * {@link #joiningExisting()}, {@link #disallowingExisting()}, {@link #suspendingExisting()} * and {@link #runner(TransactionSemantics)} can also be used for alternate semantics and options. */ @Deprecated static void run(Runnable task) { run(runOptions(), task); } /** * Runs a task in a new transaction with the default timeout. This defaults to {@link Transactional.TxType#REQUIRES_NEW} * semantics, however alternate semantics can be specified using the {@code options} parameter. * * @param options Options that apply to the new transaction * @param task The task to run in a transaction * @deprecated Use {@link #requiringNew()}, {@link #joiningExisting()}, {@link #disallowingExisting()}, * {@link #suspendingExisting()} * or {@link #runner(TransactionSemantics)} instead. */ @Deprecated static void run(RunOptions options, Runnable task) { call(options, new Callable() { @Override public Object call() throws Exception { task.run(); return null; } }); } /** * Calls a task in a new transaction with the default timeout. This defaults to {@link Transactional.TxType#REQUIRES_NEW} * semantics, however alternate semantics can be requested using {@link #call(RunOptions, Callable)}. *

* If the task throws a checked exception it will be wrapped with a {@link QuarkusTransactionException} * * @param task The task to run in a transaction * @deprecated For the same semantics, use {@link #requiringNew() * QuarkusTransaction.requiringNew().call(task)}. * {@link #joiningExisting()}, {@link #disallowingExisting()}, {@link #suspendingExisting()} * and {@link #runner(TransactionSemantics)} can also be used for alternate semantics and options. */ @Deprecated static T call(Callable task) { return call(runOptions(), task); } /** * Calls a task in a new transaction with the default timeout. This defaults to {@link Transactional.TxType#REQUIRES_NEW} * semantics, however alternate semantics can be requested using the {@code options} parameter. *

* If the task throws a checked exception it will be wrapped with a {@link QuarkusTransactionException} * * @param options Options that apply to the new transaction * @param task The task to run in a transaction * @deprecated Use {@link #requiringNew()}, {@link #joiningExisting()}, {@link #disallowingExisting()}, * {@link #suspendingExisting()} * or {@link #runner(TransactionSemantics)} instead. */ @Deprecated static T call(RunOptions options, Callable task) { return QuarkusTransactionImpl.call(options, task); } /** * @return a new RunOptions * @deprecated Use {@link #requiringNew()}, {@link #joiningExisting()}, {@link #disallowingExisting()}, * {@link #suspendingExisting()} * or {@link #runner(TransactionSemantics)} instead. */ @Deprecated static RunOptions runOptions() { return new RunOptions(); } /** * @return a new BeginOptions */ static BeginOptions beginOptions() { return new BeginOptions(); } }