拜神
看源码先拜神,事务管理的顶级接口 PlatformTransactionManager 是 Rod Johnson 和 Juergen Hoeller 两位大神写的。嗯,我看的大多源码都是拜 Juergen Hoeller 这位大神
编程式事务
接口介绍
- Spring 事务的三大接口:PlatformTransactionManager、TransactionDefinition、TransactionStatus
- TransactionTemplate 是对上述三个接口的封装,采用了模板设计模式
PlatformTransactionManager
事务管理的顶级接口。该接口其实极其简单,只有三个方法,(1)获取或创建事务;(2)提交事务;(3)回滚事务
同时为了简化事务管理器的实现,该接口提供了一个抽象类 AbstractPlatformTransactionManager,规定了事务管理器的基本框架,仅将依赖于具体平台的特性作为抽象方法留给子类实现,默认实现有 JtaTransactionManager 和 DataSourceTransactionManager。例如使用 JPA,AbstractPlatformTransactionManager 就有多一个 JpaTransactionManager 的实现
该接口也在最上边的注释上说明了,该接口是供应用直接使用的,不建议作为 API 的首选,建议使用 TransactionTemplate 或者 基于 AOP 的切面
/**
* This is the central interface in Spring's transaction infrastructure.
* Applications can use this directly, but it is not primarily meant as API:
* Typically, applications will work with either TransactionTemplate or
* declarative transaction demarcation through AOP.
*
* <p>For implementors, it is recommended to derive from the provided
* {@link org.springframework.transaction.support.AbstractPlatformTransactionManager}
* class, which pre-implements the defined propagation behavior and takes care
* of transaction synchronization handling. Subclasses have to implement
* template methods for specific states of the underlying transaction,
* for example: begin, suspend, resume, commit.
*
* <p>The default implementations of this strategy interface are
* {@link org.springframework.transaction.jta.JtaTransactionManager} and
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager},
* which can serve as an implementation guide for other transaction strategies.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 16.05.2003
* @see org.springframework.transaction.support.TransactionTemplate
* @see org.springframework.transaction.interceptor.TransactionInterceptor
*/
public interface PlatformTransactionManager {
/**
* Return a currently active transaction or create a new one, according to
* the specified propagation behavior.
* <p>Note that parameters like isolation level or timeout will only be applied
* to new transactions, and thus be ignored when participating in active ones.
* <p>Furthermore, not all transaction definition settings will be supported
* by every transaction manager: A proper transaction manager implementation
* should throw an exception when unsupported settings are encountered.
* <p>An exception to the above rule is the read-only flag, which should be
* ignored if no explicit read-only mode is supported. Essentially, the
* read-only flag is just a hint for potential optimization.
* @param definition the TransactionDefinition instance (can be {@code null} for defaults),
* describing propagation behavior, isolation level, timeout etc.
* @return transaction status object representing the new or current transaction
* @throws TransactionException in case of lookup, creation, or system errors
* @throws IllegalTransactionStateException if the given transaction definition
* cannot be executed (for example, if a currently active transaction is in
* conflict with the specified propagation behavior)
* @see TransactionDefinition#getPropagationBehavior
* @see TransactionDefinition#getIsolationLevel
* @see TransactionDefinition#getTimeout
* @see TransactionDefinition#isReadOnly
*/
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
/**
* Commit the given transaction, with regard to its status. If the transaction
* has been marked rollback-only programmatically, perform a rollback.
* <p>If the transaction wasn't a new one, omit the commit for proper
* participation in the surrounding transaction. If a previous transaction
* has been suspended to be able to create a new one, resume the previous
* transaction after committing the new one.
* <p>Note that when the commit call completes, no matter if normally or
* throwing an exception, the transaction must be fully completed and
* cleaned up. No rollback call should be expected in such a case.
* <p>If this method throws an exception other than a TransactionException,
* then some before-commit error caused the commit attempt to fail. For
* example, an O/R Mapping tool might have tried to flush changes to the
* database right before commit, with the resulting DataAccessException
* causing the transaction to fail. The original exception will be
* propagated to the caller of this commit method in such a case.
* @param status object returned by the {@code getTransaction} method
* @throws UnexpectedRollbackException in case of an unexpected rollback
* that the transaction coordinator initiated
* @throws HeuristicCompletionException in case of a transaction failure
* caused by a heuristic decision on the side of the transaction coordinator
* @throws TransactionSystemException in case of commit or system errors
* (typically caused by fundamental resource failures)
* @throws IllegalTransactionStateException if the given transaction
* is already completed (that is, committed or rolled back)
* @see TransactionStatus#setRollbackOnly
*/
void commit(TransactionStatus status) throws TransactionException;
/**
* Perform a rollback of the given transaction.
* <p>If the transaction wasn't a new one, just set it rollback-only for proper
* participation in the surrounding transaction. If a previous transaction
* has been suspended to be able to create a new one, resume the previous
* transaction after rolling back the new one.
* <p><b>Do not call rollback on a transaction if commit threw an exception.</b>
* The transaction will already have been completed and cleaned up when commit
* returns, even in case of a commit exception. Consequently, a rollback call
* after commit failure will lead to an IllegalTransactionStateException.
* @param status object returned by the {@code getTransaction} method
* @throws TransactionSystemException in case of rollback or system errors
* (typically caused by fundamental resource failures)
* @throws IllegalTransactionStateException if the given transaction
* is already completed (that is, committed or rolled back)
*/
void rollback(TransactionStatus status) throws TransactionException;
}
TransactionDefinition
接口注释解释该接口定义 Spring 的事务属性的接口,也就是说一个事务的配置都在这里做,这个接口包含了事务的传播等级、隔离级别、事务是否只读、事务超时时间
/**
* Interface that defines Spring-compliant transaction properties.
* Based on the propagation behavior definitions analogous to EJB CMT attributes.
*
* <p>Note that isolation level and timeout settings will not get applied unless
* an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED},
* {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause
* that, it usually doesn't make sense to specify those settings in other cases.
* Furthermore, be aware that not all transaction managers will support those
* advanced features and thus might throw corresponding exceptions when given
* non-default values.
*
* <p>The {@link #isReadOnly() read-only flag} applies to any transaction context,
* whether backed by an actual resource transaction or operating non-transactionally
* at the resource level. In the latter case, the flag will only apply to managed
* resources within the application, such as a Hibernate {@code Session}.
*
* @author Juergen Hoeller
* @since 08.05.2003
* @see PlatformTransactionManager#getTransaction(TransactionDefinition)
* @see org.springframework.transaction.support.DefaultTransactionDefinition
* @see org.springframework.transaction.interceptor.TransactionAttribute
*/
public interface TransactionDefinition {
/**
* Support a current transaction; create a new one if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p>This is typically the default setting of a transaction definition,
* and typically defines a transaction synchronization scope.
*/
int PROPAGATION_REQUIRED = 0;
/**
* Support a current transaction; execute non-transactionally if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> For transaction managers with transaction synchronization,
* {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
* at all, as it defines a transaction scope that synchronization might apply to.
* As a consequence, the same resources (a JDBC {@code Connection}, a
* Hibernate {@code Session}, etc) will be shared for the entire specified
* scope. Note that the exact behavior depends on the actual synchronization
* configuration of the transaction manager!
* <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
* not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
* <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
* synchronization conflicts at runtime). If such nesting is unavoidable, make sure
* to configure your transaction manager appropriately (typically switching to
* "synchronization on actual transaction").
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
*/
int PROPAGATION_SUPPORTS = 1;
/**
* Support a current transaction; throw an exception if no current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
* scope will always be driven by the surrounding transaction.
*/
int PROPAGATION_MANDATORY = 2;
/**
* Create a new transaction, suspending the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
* transaction synchronizations. Existing synchronizations will be suspended
* and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_REQUIRES_NEW = 3;
/**
* Do not support a current transaction; rather always execute non-transactionally.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
* will be suspended and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_NOT_SUPPORTED = 4;
/**
* Do not support a current transaction; throw an exception if a current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NEVER} scope.
*/
int PROPAGATION_NEVER = 5;
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@link #PROPAGATION_REQUIRED} otherwise. There is no
* analogous feature in EJB.
* <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
* specific transaction managers. Out of the box, this only applies to the JDBC
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* when working on a JDBC 3.0 driver. Some JTA providers might support
* nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
int PROPAGATION_NESTED = 6;
/**
* Use the default isolation level of the underlying datastore.
* All other levels correspond to the JDBC isolation levels.
* @see java.sql.Connection
*/
int ISOLATION_DEFAULT = -1;
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* can occur.
* <p>This level allows a row changed by one transaction to be read by another
* transaction before any changes in that row have been committed (a "dirty read").
* If any of the changes are rolled back, the second transaction will have
* retrieved an invalid row.
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
*/
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* Indicates that dirty reads are prevented; non-repeatable reads and
* phantom reads can occur.
* <p>This level only prohibits a transaction from reading a row
* with uncommitted changes in it.
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
*/
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
/**
* Indicates that dirty reads and non-repeatable reads are prevented;
* phantom reads can occur.
* <p>This level prohibits a transaction from reading a row with uncommitted changes
* in it, and it also prohibits the situation where one transaction reads a row,
* a second transaction alters the row, and the first transaction re-reads the row,
* getting different values the second time (a "non-repeatable read").
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
*/
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* are prevented.
* <p>This level includes the prohibitions in {@link #ISOLATION_REPEATABLE_READ}
* and further prohibits the situation where one transaction reads all rows that
* satisfy a {@code WHERE} condition, a second transaction inserts a row
* that satisfies that {@code WHERE} condition, and the first transaction
* re-reads for the same condition, retrieving the additional "phantom" row
* in the second read.
* @see java.sql.Connection#TRANSACTION_SERIALIZABLE
*/
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
/**
* Use the default timeout of the underlying transaction system,
* or none if timeouts are not supported.
*/
int TIMEOUT_DEFAULT = -1;
/**
* Return the propagation behavior.
* <p>Must return one of the {@code PROPAGATION_XXX} constants
* defined on {@link TransactionDefinition this interface}.
* @return the propagation behavior
* @see #PROPAGATION_REQUIRED
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
*/
int getPropagationBehavior();
/**
* Return the isolation level.
* <p>Must return one of the {@code ISOLATION_XXX} constants defined on
* {@link TransactionDefinition this interface}. Those constants are designed
* to match the values of the same constants on {@link java.sql.Connection}.
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
* transactions. Consider switching the "validateExistingTransactions" flag to
* "true" on your transaction manager if you'd like isolation level declarations
* to get rejected when participating in an existing transaction with a different
* isolation level.
* <p>Note that a transaction manager that does not support custom isolation levels
* will throw an exception when given any other level than {@link #ISOLATION_DEFAULT}.
* @return the isolation level
* @see #ISOLATION_DEFAULT
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
*/
int getIsolationLevel();
/**
* Return the transaction timeout.
* <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
* transactions.
* <p>Note that a transaction manager that does not support timeouts will throw
* an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
* @return the transaction timeout
*/
int getTimeout();
/**
* Return whether to optimize as a read-only transaction.
* <p>The read-only flag applies to any transaction context, whether backed
* by an actual resource transaction ({@link #PROPAGATION_REQUIRED}/
* {@link #PROPAGATION_REQUIRES_NEW}) or operating non-transactionally at
* the resource level ({@link #PROPAGATION_SUPPORTS}). In the latter case,
* the flag will only apply to managed resources within the application,
* such as a Hibernate {@code Session}.
* <p>This just serves as a hint for the actual transaction subsystem;
* it will <i>not necessarily</i> cause failure of write access attempts.
* A transaction manager which cannot interpret the read-only hint will
* <i>not</i> throw an exception when asked for a read-only transaction.
* @return {@code true} if the transaction is to be optimized as read-only
* @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
*/
boolean isReadOnly();
/**
* Return the name of this transaction. Can be {@code null}.
* <p>This will be used as the transaction name to be shown in a
* transaction monitor, if applicable (for example, WebLogic's).
* <p>In case of Spring's declarative transactions, the exposed name will be
* the {@code fully-qualified class name + "." + method name} (by default).
* @return the name of this transaction
* @see org.springframework.transaction.interceptor.TransactionAspectSupport
* @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
*/
@Nullable
String getName();
}
这玩意怎么用的呢。我们回头看看 @Transactional 注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
//...
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
//...
}
public enum Propagation {
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
NEVER(TransactionDefinition.PROPAGATION_NEVER),
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
public enum Isolation {
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
private final int value;
Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
所以就是注解引用了枚举对象,然后枚举对象里边的值其实取自 TransactionDefinition
TransactionStatus
记录事务的执行状态,用于flush 或者 回滚
/**
* Representation of the status of a transaction.
*
* <p>Transactional code can use this to retrieve status information,
* and to programmatically request a rollback (instead of throwing
* an exception that causes an implicit rollback).
*
* <p>Includes the {@link SavepointManager} interface to provide access
* to savepoint management facilities. Note that savepoint management
* is only available if supported by the underlying transaction manager.
*
* @author Juergen Hoeller
* @since 27.03.2003
* @see #setRollbackOnly()
* @see PlatformTransactionManager#getTransaction
* @see org.springframework.transaction.support.TransactionCallback#doInTransaction
* @see org.springframework.transaction.interceptor.TransactionInterceptor#currentTransactionStatus()
*/
public interface TransactionStatus extends SavepointManager, Flushable {
/**
* Return whether the present transaction is new; otherwise participating
* in an existing transaction, or potentially not running in an actual
* transaction in the first place.
*/
boolean isNewTransaction();
/**
* Return whether this transaction internally carries a savepoint,
* that is, has been created as nested transaction based on a savepoint.
* <p>This method is mainly here for diagnostic purposes, alongside
* {@link #isNewTransaction()}. For programmatic handling of custom
* savepoints, use the operations provided by {@link SavepointManager}.
* @see #isNewTransaction()
* @see #createSavepoint()
* @see #rollbackToSavepoint(Object)
* @see #releaseSavepoint(Object)
*/
boolean hasSavepoint();
/**
* Set the transaction rollback-only. This instructs the transaction manager
* that the only possible outcome of the transaction may be a rollback, as
* alternative to throwing an exception which would in turn trigger a rollback.
* <p>This is mainly intended for transactions managed by
* {@link org.springframework.transaction.support.TransactionTemplate} or
* {@link org.springframework.transaction.interceptor.TransactionInterceptor},
* where the actual commit/rollback decision is made by the container.
* @see org.springframework.transaction.support.TransactionCallback#doInTransaction
* @see org.springframework.transaction.interceptor.TransactionAttribute#rollbackOn
*/
void setRollbackOnly();
/**
* Return whether the transaction has been marked as rollback-only
* (either by the application or by the transaction infrastructure).
*/
boolean isRollbackOnly();
/**
* Flush the underlying session to the datastore, if applicable:
* for example, all affected Hibernate/JPA sessions.
* <p>This is effectively just a hint and may be a no-op if the underlying
* transaction manager does not have a flush concept. A flush signal may
* get applied to the primary resource or to transaction synchronizations,
* depending on the underlying resource.
*/
@Override
void flush();
/**
* Return whether this transaction is completed, that is,
* whether it has already been committed or rolled back.
* @see PlatformTransactionManager#commit
* @see PlatformTransactionManager#rollback
*/
boolean isCompleted();
}
TransactionTemplate
TransactionTemplate 注释的接是就是简化程序化事务划分和事务异常处理的模板类
比如它继承了 DefaultTransactionDefinition, DefaultTransactionDefinition 定义了事务默认的 TransactionDefinition
它里边核心的方法是:execute(TransactionCallback action)
/**
* Template class that simplifies programmatic transaction demarcation and
* transaction exception handling.
*
* <p>The central method is {@link #execute}, supporting transactional code that
* implements the {@link TransactionCallback} interface. This template handles
* the transaction lifecycle and possible exceptions such that neither the
* TransactionCallback implementation nor the calling code needs to explicitly
* handle transactions.
*
* <p>Typical usage: Allows for writing low-level data access objects that use
* resources such as JDBC DataSources but are not transaction-aware themselves.
* Instead, they can implicitly participate in transactions handled by higher-level
* application services utilizing this class, making calls to the low-level
* services via an inner-class callback object.
*
* <p>Can be used within a service implementation via direct instantiation with
* a transaction manager reference, or get prepared in an application context
* and passed to services as bean reference. Note: The transaction manager should
* always be configured as bean in the application context: in the first case given
* to the service directly, in the second case given to the prepared template.
*
* <p>Supports setting the propagation behavior and the isolation level by name,
* for convenient configuration in context definitions.
*
* @author Juergen Hoeller
* @since 17.03.2003
* @see #execute
* @see #setTransactionManager
* @see org.springframework.transaction.PlatformTransactionManager
*/
@SuppressWarnings("serial")
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private PlatformTransactionManager transactionManager;
/**
* Construct a new TransactionTemplate for bean usage.
* <p>Note: The PlatformTransactionManager needs to be set before
* any {@code execute} calls.
* @see #setTransactionManager
*/
public TransactionTemplate() {
}
/**
* Construct a new TransactionTemplate using the given transaction manager.
* @param transactionManager the transaction management strategy to be used
*/
public TransactionTemplate(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* Construct a new TransactionTemplate using the given transaction manager,
* taking its default settings from the given transaction definition.
* @param transactionManager the transaction management strategy to be used
* @param transactionDefinition the transaction definition to copy the
* default settings from. Local properties can still be set to change values.
*/
public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) {
super(transactionDefinition);
this.transactionManager = transactionManager;
}
/**
* Set the transaction management strategy to be used.
*/
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* Return the transaction management strategy to be used.
*/
@Nullable
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
@Override
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
// 判断 PlatformTransactionManager 不为空
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
//
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
// 调用 platformTransactionManager.getTransaction(this),上边讲过 PlatformTransactionManager 的方法在 AbstractPlatformTransactionManager 都有实现
// 遗留一:下边会讲 AbstractPlatformTransactionManager 这里不展开 只需要知道这里是创建了一个事务
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
// 就是执行业务代码了
// 遗留二:下边会讲 TransactionCallback
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
// 事务回滚,方法就在下边,其实就是调了 platformTransactionManager.rollback
// 遗留一
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
// 事务回滚 对未知异常做了封装
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 事务提交
// 遗留一
this.transactionManager.commit(status);
return result;
}
}
/**
* Perform a rollback, handling rollback exceptions properly.
* @param status object representing the transaction
* @param ex the thrown application exception or error
* @throws TransactionException in case of a rollback error
*/
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
logger.debug("Initiating transaction rollback on application exception", ex);
try {
// 遗留一
this.transactionManager.rollback(status);
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
@Override
public boolean equals(Object other) {
return (this == other || (super.equals(other) && (!(other instanceof TransactionTemplate) ||
getTransactionManager() == ((TransactionTemplate) other).getTransactionManager())));
}
}
举一个我们项目使用 TransactionTemplate 的例子
这里为什么要用 TransactionTemplate 是因为 @PostConstruct 注解上边加事务注解是不生效的。具体原因等讲完遗留一就明白了
@PostConstruct
public void init() {
TransactionTemplate tmpl = new TransactionTemplate(jpaTransactionManager);
tmpl.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
FwUserTokenInfo userTokenInfo = serviceAccountService.getServiceAccount();
AccessControlContext.setAcUser(userTokenInfo.getUser());
AccessControlDefaultPolicyUploader.super.init();
}
});
}
TransactionCallback
这里先看遗留二吧,比较简单
注释写的很清楚,事务代码的回调接口,与 TransactionTemplate 一起使用,通常作为方法实现中的匿名类
/**
* Callback interface for transactional code. Used with {@link TransactionTemplate}'s
* {@code execute} method, often as anonymous class within a method implementation.
*
* <p>Typically used to assemble various calls to transaction-unaware data access
* services into a higher-level service method with transaction demarcation. As an
* alternative, consider the use of declarative transaction demarcation (e.g. through
* Spring's {@link org.springframework.transaction.annotation.Transactional} annotation).
*
* @author Juergen Hoeller
* @since 17.03.2003
* @see TransactionTemplate
* @see CallbackPreferringPlatformTransactionManager
* @param <T> the result type
*/
@FunctionalInterface
public interface TransactionCallback<T> {
/**
* Gets called by {@link TransactionTemplate#execute} within a transactional context.
* Does not need to care about transactions itself, although it can retrieve and
* influence the status of the current transaction via the given status object,
* e.g. setting rollback-only.
* <p>Allows for returning a result object created within the transaction, i.e. a
* domain object or a collection of domain objects. A RuntimeException thrown by the
* callback is treated as application exception that enforces a rollback. Any such
* exception will be propagated to the caller of the template, unless there is a
* problem rolling back, in which case a TransactionException will be thrown.
* @param status associated transaction status
* @return a result object, or {@code null}
* @see TransactionTemplate#execute
* @see CallbackPreferringPlatformTransactionManager#execute
*/
@Nullable
T doInTransaction(TransactionStatus status);
}
// 抽象方法实现了 TransactionCallback,我上边的例子其实就是使用了它
/**
* Simple convenience class for TransactionCallback implementation.
* Allows for implementing a doInTransaction version without result,
* i.e. without the need for a return statement.
*
* @author Juergen Hoeller
* @since 28.03.2003
* @see TransactionTemplate
*/
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
@Override
@Nullable
public final Object doInTransaction(TransactionStatus status) {
doInTransactionWithoutResult(status);
return null;
}
/**
* Gets called by {@code TransactionTemplate.execute} within a transactional
* context. Does not need to care about transactions itself, although it can retrieve
* and influence the status of the current transaction via the given status object,
* e.g. setting rollback-only.
* <p>A RuntimeException thrown by the callback is treated as application
* exception that enforces a rollback. An exception gets propagated to the
* caller of the template.
* <p>Note when using JTA: JTA transactions only work with transactional
* JNDI resources, so implementations need to use such resources if they
* want transaction support.
* @param status associated transaction status
* @see TransactionTemplate#execute
*/
protected abstract void doInTransactionWithoutResult(TransactionStatus status);
}
AbstractPlatformTransactionManager
遗留一, 这里比较重要了,注释也写得很清楚,是 Spring 处理事务的抽象基类,是具体平台事务的基础(也就是你想自定义一套事务管理最好以它为基础)
直接看源码吧
源码太长,分开看吧
/**
* Abstract base class that implements Spring's standard transaction workflow,
* serving as basis for concrete platform transaction managers like
* {@link org.springframework.transaction.jta.JtaTransactionManager}.
*
* <p>This base class provides the following workflow handling:
* <ul>
* <li>determines if there is an existing transaction;
* <li>applies the appropriate propagation behavior;
* <li>suspends and resumes transactions if necessary;
* <li>checks the rollback-only flag on commit;
* <li>applies the appropriate modification on rollback
* (actual rollback or setting rollback-only);
* <li>triggers registered synchronization callbacks
* (if transaction synchronization is active).
* </ul>
*
* <p>Subclasses have to implement specific template methods for specific
* states of a transaction, e.g.: begin, suspend, resume, commit, rollback.
* The most important of them are abstract and must be provided by a concrete
* implementation; for the rest, defaults are provided, so overriding is optional.
*
* <p>Transaction synchronization is a generic mechanism for registering callbacks
* that get invoked at transaction completion time. This is mainly used internally
* by the data access support classes for JDBC, Hibernate, JPA, etc when running
* within a JTA transaction: They register resources that are opened within the
* transaction for closing at transaction completion time, allowing e.g. for reuse
* of the same Hibernate Session within the transaction. The same mechanism can
* also be leveraged for custom synchronization needs in an application.
*
* <p>The state of this class is serializable, to allow for serializing the
* transaction strategy along with proxies that carry a transaction interceptor.
* It is up to subclasses if they wish to make their state to be serializable too.
* They should implement the {@code java.io.Serializable} marker interface in
* that case, and potentially a private {@code readObject()} method (according
* to Java serialization rules) if they need to restore any transient state.
*
* @author Juergen Hoeller
* @since 28.03.2003
* @see #setTransactionSynchronization
* @see TransactionSynchronizationManager
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
@SuppressWarnings("serial")
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
// 对 这里就是给你看看注释,然后拜拜大神 Juergen Hoeller
}
AbstractPlatformTransactionManager
/*
* @author Juergen Hoeller
*/
@SuppressWarnings("serial")
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
//---------------------------------------------------------------------
// Implementation of PlatformTransactionManager
//---------------------------------------------------------------------
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// do 开头。spring 中 do 开头的方法都是干实事的
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 判断事务是否存在且活跃
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事务状态
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开始事务
doBegin(transaction, definition);
// 事务状态同步
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
/**
* This implementation of rollback handles participating in existing
* transactions. Delegates to {@code doRollback} and
* {@code doSetRollbackOnly}.
* @see #doRollback
* @see #doSetRollbackOnly
*/
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
processRollback(defStatus, false);
}
/**
* Process an actual rollback.
* The completed flag has already been checked.
* @param status object representing the transaction
* @throws TransactionException in case of rollback failure
*/
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
cleanupAfterCompletion(status);
}
}
/**
* This implementation of commit handles participating in existing
* transactions and programmatic rollback requests.
* Delegates to {@code isRollbackOnly}, {@code doCommit}
* and {@code rollback}.
* @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
* @see #doCommit
* @see #rollback
*/
@Override
public final void commit(TransactionStatus status) throws TransactionException {
// 判断当前事务状态是否已经结束
if (status.isCompleted()) {
throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 判断当前事务是否有回滚标识
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
// 事务回滚
processRollback(defStatus, false);
return;
}
// 全局事务 且被标记为需要回滚
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
// 事务回滚
processRollback(defStatus, true);
return;
}
// 事务提交
processCommit(defStatus);
}
/**
* Process an actual commit.
* Rollback-only flags have already been checked and applied.
* @param status object representing the transaction
* @throws TransactionException in case of commit failure
*/
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
// 空方法,没找到实现
prepareForCommit(status);
// 事务提交前,触发回调
triggerBeforeCommit(status);
// 事务完成前,触发回调
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
// 是否是新事务,如果是新事务,将执行提交操作,比如传播行为是 REQUIRED 中嵌套了一个 REQUIRED,那么内部的事务就不是新的事务,外部的事务是新事务
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
// 提交事务
// 扩展一
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
// 事务完成之后,执行一些回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
// 提交过程中有异常,执行回滚操作
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
// 事务完成之后,执行一些回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
// 提交过程中有异常,执行回滚操作
doRollbackOnCommitException(status, ex);
throw ex;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
// 事务 commit 之后,执行一些回调
triggerAfterCommit(status);
}
finally {
// 事务完成之后,执行一些回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
// 事务执行完毕之后,执行一些清理操作
cleanupAfterCompletion(status);
}
}
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
// 将事务状态置为已完成
status.setCompleted();
// 是否是新的事务同步
if (status.isNewSynchronization()) {
// 扩展二 清空当前线程 ThreadLocal 里边的所有东西
TransactionSynchronizationManager.clear();
}
// 是否是新的事务
if (status.isNewTransaction()) {
// 提交事务并清理
doCleanupAfterCompletion(status.getTransaction());
}
// 当前事务状态是否被挂起
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
// 恢复被挂起的事务
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
// 抽象方法,所以还要往下走
// 该方法作用:返回当前事务的事务状态
// 它的实现有很多,但里边的逻辑都差不多,毕竟只是拿到当前事务状态:CciLocalTransactionManager DataSourceTransactionManager HibernateTransactionManager JpaTransactionManager JtaTransactionManager...
// 扩展一:找一个实现看一下
protected abstract Object doGetTransaction() throws TransactionException;
// 扩展一
protected abstract void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException;
// 扩展一
protected abstract void doCommit(DefaultTransactionStatus status) throws TransactionException;
// 扩展一
protected void doCleanupAfterCompletion(Object transaction) {};
// 扩展一
protected abstract void doRollback(DefaultTransactionStatus status) throws TransactionException;
}
// 扩展一
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
protected Object doGetTransaction() {
// 构造了个 DataSourceTransactionObject 对象,对象里边没啥就俩字段:private boolean newConnectionHolder;和 private boolean mustRestoreAutoCommit;
DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
// 默认是false:private boolean nestedTransactionAllowed = false; 表示是否允许嵌套事务
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
// 这一个是核心,无论哪种实现都需要调这个方法,区别只是结果做了强转
// 这里需要注意一点就是入参传入的是 DataSource 对象,然后返回当前线程资源的持有者 ConnectionHolder,后期连接归 ConnectionHolder 管
// 扩展二
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
// 将 conHolder 丢到 DataSourceTransactionObject 中,第二个参数表示是否是一个新的连接,这里肯定为 false,因为通过 datasource 获取的连接才是新的连接
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
protected DataSource obtainDataSource() {
DataSource dataSource = this.getDataSource();
Assert.state(dataSource != null, "No DataSource set");
return dataSource;
}
@Nullable
public DataSource getDataSource() {
return this.dataSource;
}
/**
* This implementation sets the isolation level but ignores the timeout.
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
// 强转成 DataSource 事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 获取一个事务的连接
// 非常重要!!!!!!!!!! 一次生产事故就是这里理解不到位引起的。即你线程超时时间在创建事务的时候就已经开始计时了,并不是你开始commit时候,因此如果你代码里边一些长时间执行的代码。可能还没有走到操作数据库的代码位置,就已经抛了数据库连接超时的异常,如果这时候前边的代码再阻塞线程。数据库连接被耗尽后整个服务就 down 了!!!!!
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 将事务的连接放到 DataSourceTransactionObject 对象中,并标记为新的连接
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 标记事务连接为 true
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
// 获取事务的连接
con = txObject.getConnectionHolder().getConnection();
// 获取事务的隔离级别,并赋值。实现比较简单不展开了
// 这里边其实做了两件事:(1)// Set read-only flag; (2)// Apply specific isolation level, if any.
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
// 改为不自动提交
con.setAutoCommit(false);
}
// 设置 TransactionSynchronizationManager 中的一些变量值
prepareTransactionalConnection(con, definition);
// 设置来连接对象可用
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// 设置连接对象的超时时间
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
// 核心方法!!! 绑定线程!!!
if (txObject.isNewConnectionHolder()) {
// 扩展二
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
// 获取当前线程对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// 获取当前连接
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
// 提交事务 具体不展开了
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
@Override
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// Remove the connection holder from the thread, if exposed.
if (txObject.isNewConnectionHolder()) {
// 解绑资源,对应前边的 bindResource,就是在 ThreadLocal 里边删掉资源
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// Reset connection.
// 重置连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
DataSourceUtils.releaseConnection(con, this.dataSource);
}
// 清理事务
txObject.getConnectionHolder().clear();
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
// 回滚 具体不展开了
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
}
// 扩展二
// 这也是一个比较核心的抽象类
public abstract class TransactionSynchronizationManager {
// 存储事务资源信息
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
// 存储事务过程中的一些回调接口(TransactionSynchronization接口,这个可以在事务的过程中给开发者提供一些回调用的)
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");
// 存储当前正在运行的事务的名称
private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<>("Current transaction name");
// 存储当前正在运行的事务是否是只读的
private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<>("Current transaction read-only status");
// 存储当前正在运行的事务的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<>("Current transaction isolation level");
// 存储当前正在运行的事务是否是活动状态,事务启动的时候会被激活
private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<>("Actual transaction active");
/**
* Retrieve a resource for the given key that is bound to the current thread.
* @param key the key to check (usually the resource factory)
* @return a value bound to the current thread (usually the active
* resource object), or {@code null} if none
* @see ResourceTransactionManager#getResourceFactory()
*/
// 返回当前线程的资源持有者
@Nullable
public static Object getResource(Object key) {
// 扩展三 最后都是调用了扩展三的代码,获取 DataSource 的 bean
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// 获取连接对象
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
return value;
}
/**
* Actually check the value of the resource that is bound for the given key.
*/
@Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
// 最开始必然走这里,因为没 put 进 resources
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
/**
* Bind the given resource for the given key to the current thread.
* @param key the key to bind the value to (usually the resource factory)
* @param value the value to bind (usually the active resource object)
* @throws IllegalStateException if there is already a value bound to the thread
* @see ResourceTransactionManager#getResourceFactory()
*/
public static void bindResource(Object key, Object value) throws IllegalStateException {
// 获取当前线程
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
// 更新到 ThreadLocal 中
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]");
}
}
/**
* Clear the entire transaction synchronization state for the current thread:
* registered synchronizations as well as the various transaction characteristics.
* @see #clearSynchronization()
* @see #setCurrentTransactionName
* @see #setCurrentTransactionReadOnly
* @see #setCurrentTransactionIsolationLevel
* @see #setActualTransactionActive
*/
public static void clear() {
synchronizations.remove();
currentTransactionName.remove();
currentTransactionReadOnly.remove();
currentTransactionIsolationLevel.remove();
actualTransactionActive.remove();
}
}
// 扩展三
public class DefaultScopedObject implements ScopedObject, Serializable {
private final ConfigurableBeanFactory beanFactory;
private final String targetBeanName;
/**
* Creates a new instance of the {@link DefaultScopedObject} class.
* @param beanFactory the {@link ConfigurableBeanFactory} that holds the scoped target object
* @param targetBeanName the name of the target bean
*/
public DefaultScopedObject(ConfigurableBeanFactory beanFactory, String targetBeanName) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
Assert.hasText(targetBeanName, "'targetBeanName' must not be empty");
this.beanFactory = beanFactory;
this.targetBeanName = targetBeanName;
}
@Override
public Object getTargetObject() {
return this.beanFactory.getBean(this.targetBeanName);
}
@Override
public void removeFromScope() {
this.beanFactory.destroyScopedBean(this.targetBeanName);
}
}
响应式事务
未完待续。。。