@Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { Sql sql = this.sql; if (method.getDeclaringClass() == SqlStreamHolder.class) { return sql; } TransactionStatus transactionStatus = null; try { transactionStatus = TransactionAspectSupport.currentTransactionStatus(); } catch (NoTransactionException e) { if (FAIL_WITHOUT_TRANSACTION) { throw e; } } if (transactionStatus instanceof SqlStreamTransactionStatus) { sql = ((SqlStreamTransactionStatus) transactionStatus).transaction; } return method.invoke(sql, objects); }
@Override public void before(Method method, Object[] args, Object target) throws Throwable { // do transaction checks if (requireTransactionContext) { TransactionInterceptor.currentTransactionStatus(); } else { try { TransactionInterceptor.currentTransactionStatus(); throw new RuntimeException("Shouldn't have a transaction"); } catch (NoTransactionException ex) { // this is Ok } } super.before(method, args, target); }
private void checkNoStatusOnThread() { try { TransactionAspectSupport.currentTransactionStatus(); fail("Spring transaction info is present outside of transaction boundaries"); } catch (NoTransactionException e) { // expected } }
/** * Return the transaction status of the current method invocation. * Mainly intended for code that wants to set the current transaction * rollback-only but not throw an application exception. * @throws NoTransactionException if the transaction info cannot be found, * because the method was invoked outside an AOP invocation context */ public static TransactionStatus currentTransactionStatus() throws NoTransactionException { TransactionInfo info = currentTransactionInfo(); if (info == null) { throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope"); } return currentTransactionInfo().transactionStatus; }
public Object[] exec() { return (Object[]) execute(new RedisCallback<Jedis>() { public Object doInRedis(Jedis redis) { if (transaction != null) { List<Object> results = transaction.exec(); try { return results.toArray(new Object[results.size()]); } finally { transaction = null; } } throw new NoTransactionException("No transaction started. Call multi() first!"); } }); }
/** * Return the transaction status of the current method invocation. * Mainly intended for code that wants to set the current transaction * rollback-only but not throw an application exception. * @throws NoTransactionException if the transaction info cannot be found, * because the method was invoked outside an AOP invocation context */ public static TransactionStatus currentTransactionStatus() throws NoTransactionException { TransactionInfo info = currentTransactionInfo(); if (info == null || info.transactionStatus == null) { throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope"); } return info.transactionStatus; }
protected void checkTransactionStatus(boolean expected) { try { TransactionInterceptor.currentTransactionStatus(); if (!expected) { fail("Should have thrown NoTransactionException"); } } catch (NoTransactionException ex) { if (expected) { fail("Should have current TransactionStatus"); } } }
/** * Gets the current transaction info, or null if none exists. * <p> * A check is done to ensure that the transaction info on the stack is exactly * the same instance used when this transaction was started. * The internal status is also checked against the transaction info. * These checks ensure that the transaction demarcation is done correctly and that * thread safety is adhered to. * * @return Returns the current transaction */ private TransactionInfo getTransactionInfo() { // a few quick self-checks if (threadId < 0 && internalStatus != Status.STATUS_NO_TRANSACTION) { throw new RuntimeException("Transaction has been started but there is no thread ID"); } else if (threadId >= 0 && internalStatus == Status.STATUS_NO_TRANSACTION) { throw new RuntimeException("Transaction has not been started but a thread ID has been recorded"); } TransactionInfo txnInfo = null; try { txnInfo = TransactionAspectSupport.currentTransactionInfo(); // we are in a transaction } catch (NoTransactionException e) { // No transaction. It is possible that the transaction threw an exception during commit. } // perform checks for active transactions if (internalStatus == Status.STATUS_ACTIVE) { if (Thread.currentThread().getId() != threadId) { // the internally stored transaction info (retrieved in begin()) should match the info // on the thread throw new RuntimeException("UserTransaction may not be accessed by multiple threads"); } else if (txnInfo == null) { // internally we recorded a transaction starting, but there is nothing on the thread throw new RuntimeException("Transaction boundaries have been made to overlap in the stack"); } else if (txnInfo != internalTxnInfo) { // the transaction info on the stack isn't the one we started with throw new RuntimeException("UserTransaction begin/commit mismatch"); } } return txnInfo; }
/** * Subclasses can use this to return the current TransactionInfo. * Only subclasses that cannot handle all operations in one method, * such as an AspectJ aspect involving distinct before and after advice, * need to use this mechanism to get at the current TransactionInfo. * An around advice such as an AOP Alliance MethodInterceptor can hold a * reference to the TransactionInfo throughout the aspect method. * <p>A TransactionInfo will be returned even if no transaction was created. * The {@code TransactionInfo.hasTransaction()} method can be used to query this. * <p>To find out about specific transaction characteristics, consider using * TransactionSynchronizationManager's {@code isSynchronizationActive()} * and/or {@code isActualTransactionActive()} methods. * @return TransactionInfo bound to this thread, or {@code null} if none * @see TransactionInfo#hasTransaction() * @see org.springframework.transaction.support.TransactionSynchronizationManager#isSynchronizationActive() * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive() */ protected static TransactionInfo currentTransactionInfo() throws NoTransactionException { return transactionInfoHolder.get(); }