This is the fifth day of my participation in Gwen Challenge

We all know that Spring’s transactions are implemented by Aop, and that Spring creates a proxy object and then implements the specific logic by invoking the Invoke method via TransactionIntercept. We’ll look at that later

I. Related concepts

Let’s review the well-worn ACID nature of transactions

A: Atomicity: Operations cannot be split, either all succeed or all fail. C: consistency: transactions transfer data from one consistent state to another consistent state I: Isolation: Isolation prevents inconsistencies caused by cross-execution when multiple transactions are executed concurrently. D: Durability: Modifications to data are permanent.

Transaction isolation level:

Read Uncommit: A possible dirty Read, that is, Read data not committed by another transaction is Read commit: a possible problem of Repeatable Read, that is, the results of two reads are inconsistent. Phantom reading can occur and data can be read from other committed transactions after update. (MVCC related, shared later) serializable

Spring transaction apis

  1. Transaction definition: Contains information such as the isolation level of the transaction and the propagation behavior of the transaction

  1. Transaction properties: Implements an extension of the rollback rule

TransactionAttribute extends TransactionDefinition

boolean rollbackOn(Throwable ex);

  1. Transaction manager:
public interface PlatformTransactionManager {

	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)throws TransactionException;

	void commit(TransactionStatus status) throws TransactionException;

	void rollback(TransactionStatus status) throws TransactionException;

}
Copy the code
  1. Transaction runtime status:
public interface TransactionStatus extends SavepointManager.Flushable {

	boolean isNewTransaction(a);

	boolean hasSavepoint(a);// Rollback to a point

	void setRollbackOnly(a);

	boolean isRollbackOnly(a);

	@Override
	void flush(a);

	boolean isCompleted(a);

}
Copy the code
  1. TransactionInterceptor: TransactionInterceptor

  1. TransactionAspectSupport: TransactionAspectSupport

The inner class TransactionInfo encapsulates the properties of the transaction.

protected final class TransactionInfo {

		@Nullable
		private final PlatformTransactionManager transactionManager;

		@Nullable
		private final TransactionAttribute transactionAttribute;

		private final String joinpointIdentification;

		@Nullable
		private TransactionStatus transactionStatus;

		@Nullable
		private TransactionInfo oldTransactionInfo;

		public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
				@Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {

			this.transactionManager = transactionManager;
			this.transactionAttribute = transactionAttribute;
			this.joinpointIdentification = joinpointIdentification;
		}

		public PlatformTransactionManager getTransactionManager(a) {
			Assert.state(this.transactionManager ! =null."No PlatformTransactionManager set");
			return this.transactionManager;
		}

		@Nullable
		public TransactionAttribute getTransactionAttribute(a) {
			return this.transactionAttribute;
		}

		/** * Return a String representation of this joinpoint (usually a Method call) * for use in logging. */
		public String getJoinpointIdentification(a) {
			return this.joinpointIdentification;
		}

		public void newTransactionStatus(@Nullable TransactionStatus status) {
			this.transactionStatus = status;
		}

		@Nullable
		public TransactionStatus getTransactionStatus(a) {
			return this.transactionStatus;
		}

		/** * Return whether a transaction was created by this aspect, * or whether we just have a placeholder to keep ThreadLocal stack integrity. */
		public boolean hasTransaction(a) {
			return (this.transactionStatus ! =null);
		}

		private void bindToThread(a) {
			// Expose current TransactionStatus, preserving any existing TransactionStatus
			// for restoration after this transaction is complete.
			this.oldTransactionInfo = transactionInfoHolder.get();
			transactionInfoHolder.set(this);
		}

		private void restoreThreadLocalStatus(a) {
			// Use stack to restore old transaction TransactionInfo.
			// Will be null if none was set.
			transactionInfoHolder.set(this.oldTransactionInfo);
		}

		@Override
		public String toString(a) {
			return (this.transactionAttribute ! =null ? this.transactionAttribute.toString() : "No transaction"); }}Copy the code

TransactionInterceptor, the TransactionInterceptor mentioned above, processes transactions by calling the invokeWithinTransaction method of its parent class TransactionAspectSupport. This method supports both declarative and programmatic transactions.

@Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.Class<? > targetClass = (invocation.getThis() ! =null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
Copy the code
protected Object invokeWithinTransaction(Method method, @NullableClass<? > targetClass,final InvocationCallback invocation) throws Throwable {
    // Query the target method transaction attributes, determine the transaction manager, construct the join point identifier (used to confirm the transaction name)
    TransactionAttributeSource tas = getTransactionAttributeSource();
    finalTransactionAttribute txAttr = (tas ! =null ? tas.getTransactionAttribute(method, targetClass) : null);
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    // Transaction fetch
 TransactionInfotxInfo=createTransactionIfNecessary(tm,txAttr,joinpointIdentification);

    Object retVal;
    try {
             // Execute the target method via a callback
            retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
            // The target method throws an exception and performs a transaction commit or rollback depending on the exception type
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
    }
    finally {
            // Clear the current thread transaction information
            cleanupTransactionInfo(txInfo);
    }
    // The target method executed successfully and committed the transaction
    commitTransactionAfterReturning(txInfo);
    return retVal;
}
Copy the code

Above, thanks for reading.