Spring源码学习(6)- 事务解析
Spring中事务,是使用AOP切面技术来实现的
事务的使用
使用事务时,要不就是在配置文件中配置,要不就是使用注解方式
使用注解方式的话,需要用到@EnableTransactionMangement注解,这个注解就显示的添加了注解事务功能,但是我们还需要定义数据源和事务管理平台
@EnableTransactionManagement
public class EnableTransactionManagementConfig{
// 数据源的定义
@Bean
public DataSource comboPooledDataSource(){
ComboPooledDataSource comboPooledDataSouce = new ComboPooledDataSource();
/*
中间一系列的操作
*/
return comboPooledDataSouce;
}
// 定义事务管理平台
@Bean
public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
}
@EnableTransactionMangement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
跟Aop的注解一样。有个@Import注解,导入TransactionManagementConfigurationSelector 这个类
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
// 如果没有设置AdviceMode,默认是AdviceMode.PROXY
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
@Import导入,是在refresh()过程中,invokeBeanFactoryPostProcessors() 这个方法去完成的
然后遍历执行实现了BeanDefinitionRegistryPostProcessor接口的子类d的postProcessBeanDefinitionRegistry()方法
主要的就是ConfigurationClassPostProcessor这个类,经过一系列操作后,会调用TransactionManagementConfigurationSelector 的selectImports()方法,然后导入AutoProxyRegistrar跟ProxyTransactionManagementConfiguration类
ProxyTransactionManagementConfiguration 这个类就是来加载数据源跟事务管理平台的
在jdbc中可得知事务是由connection对象控制的,所以connection对象和事务是绑定的
当用户请求过来时,需要数据库连接,来执行sql语句,所以用户请求跟数据库连接是绑定的
Spring事务传播属性
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),
/*
如果当前存在事务,则在嵌套事务内执行。
如果当前没有事务,则执行与REQUIRED类似的操作
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {this.value = value;}
public int value() {return this.value;}
}
其中最常见的,就是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_ESTED这三种。
事务的传播属性,是spring特有的,是spring用来控制方法事务的一种手段
传播属性的事务控制
使用@EnableTransactionManagement后,会导入TransactionManagementConfigurationSelector 这个类,然后在容器refresh的时候,会创建ProxyTransactionManagementConfiguration类。
ProxyTransactionManagementConfiguration 这个类,就是创建事务Advice跟事务切面实例的
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/*
* 明显是创建事务切面实例
* BeanFactoryTransactionAttributeSourceAdvisor
*
* */
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
// 设置通知类
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/*
* 创建事务advice
* TransactionInterceptor
* */
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
// 事务管理器要跟数据源挂钩,所以需要自己定义
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
事务源码解析
TransactionInterceptor 这个类是事务企切面的Advice,所有有关spring的事务控制逻辑都在这个类里面,点进去看invoke方法,调用的是父类 TransactionAspectSupport 的 invokeWithinTransaction()发方法
可以将该方法分为几个部分
1.事务相关的处理
2.方法调用
3.提交或者回滚事务
4.释放资源和重新建立绑定关系
事务相关的处理
获取事务属性
// 获取事务属性类 AnnotationTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
// 获取方法上面有@Transactional注解的属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
创建事务对象
/*
获取事务管理器
1.先尝试从缓存中获取,有则直接返回缓存中的事务管理器
2.如果缓存中不存在,则解析方法上@Transactional上的参数,并封装成RuleBasedTransactionAttribute对象返回
3.放入缓存中
*/
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
createTransactionIfNecessary()
开启事务
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 开启事务
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 创建事务信息对象,记录新老事务信息对象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
getTransaction()
将该方法分成几个部分
1.获取DataSourceTransactionObject
// 获取DataSourceTransactionObject
Object transaction = doGetTransaction();
// -----------------------------------------
protected Object doGetTransaction() {
// 管理connection对象,创建回滚点,按照回滚点回滚,释放回滚点
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// DataSourceTransactionManager默认是允许嵌套事务的
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// obtainDataSource() 获取数据源对象,其实就是数据库连接块对象
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
2.判断当前是否有事务存在
// 判断当前是否有事务存在,如果有,进行一系列操作返回事务对象。第一次是不存在事务的
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// --------------------------
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
3.创建事务对象 DefaultTransactionStatus,这个类中有个属性很重要,就是newTransaction属性,
类型是boolean。
- 如果为true,就代表当前事务允许单独提交和回滚,一般第一次创建事务,或者事务传播属性为PROPAGATION_REQUIRES_NEW的时候
- 如果为false,则当前事务不能单独提交和回滚
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);
// 开启事务,重点看看 DataSourceTransactionObject
doBegin(transaction, definition);
// 开启事务后,改变事务状态
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
4.开启事务doBegin()
- 首先从数据源连接池中,获取数据库连接,并把连接封装成ConnectionHolder,设置到事务对象中
// 如果没有数据库连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 从连接池里面获取连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 把连接包装成ConnectionHolder,然后设置到事务对象中
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
- 关闭自动提交,这个就是开启了事务
con.setAutoCommit(false);
- 建立当前线程与数据源的绑定关系(数据源与连接存入一个map中,)
// 如果是新创建的事务,则建立当前线程和数据库连接的关系
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
事务就开启完毕了
当第二次进来的时候,又有事务的话,就会进入下面的逻辑
// 伪代码
class TransactionaDemoA{
@Autowired
TransactionaDemoB demoB;
@Transactional
void a(){
demoB.b();
}
}
class TransactionaDemoB{
@Transactional
void b(){// ......}
}
// 这种情况下,会进入下面的代码
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// -------------------------------
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 不允许有事务,直接异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 挂起当前事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 修改事务状态信息,把事务的一些信息存储到当前线程中,ThreadLocal中
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 挂起
SuspendedResourcesHolder suspendedResources = suspend(transaction);
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 beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 默认是可以嵌套事务的
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建回滚点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
重点看两种传播特性:
PROPAGATION_REQUIRES_NEW:
如果没有事务,自己创建一个事务
如果有事务,挂起当前事务,并创建新的事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
// 挂起
SuspendedResourcesHolder suspendedResources = suspend(transaction);
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 beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// ------------------suspend()----------------
/*
1.获取当前线程上一个数据库连接
2.将事务的属性收集起来
3.封装成SuspendedResourcesHolder对象
*/
if (transaction != null) {
// 把connectionHolder设置为空,其实
suspendedResources = doSuspend(transaction);
}
// 做数据还原操作
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
// -----------------doSuspend()---------------------
/*
该方法,就是根据数据源,去当前线程寻找对应的map,key为数据源,value为数据库连接
1.先在ThreadLocal获取map。
2.判断是否获取到,如果获取到,从map中删除并获取数据库连接
3.从ThreadLocal中删除当前Map
4.返回获取到的数据库连接
*/
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
//解除绑定关系
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
PROPAGATION_NESTED:
嵌套事务,就是按照回滚点来回滚事务的
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 默认是可以嵌套事务的
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建回滚点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
方法调用
aop的链式调用过程,如果不存在advice了,就会调用被代理方法,执行相应的业务操作
retVal = invocation.proceedWithInvocation();
提交或者回滚事务
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 方法调用
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 事务回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
// 事务提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
事务回滚
可以看出,如果抛异常,不是一定回滚,会首先判断抛的异常,是否在回滚的返回中,如果不在还是会提交事务的
// catch部分被省略了
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
}
事务提交
- 如果有回滚点,清除回滚点,等其他事务提交
- 如果newTransaction属性为true的话,就直接提交事务,如果不是的话,等其他事务提交
newTransaction属性是在创建事务的时候,传入的
public final void commit(TransactionStatus status) throws TransactionException {
// 省略其他代码
processCommit(defStatus);
}
// -------------processCommit()--------------------
```java
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
// 如果都是PROPAGATION_REQUIRED,最外层的才会走进来统一提交,如果是PROPAGATION_REQUIRES_NEW,每一个事务都会进来
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
释放资源和重新建立绑定关系
AbstractPlatformTransactionManager.processCommit()方法中,在事务提交之后的finally语句块里
- 首先,判断当前事务的newTransaction 是否为true,如果为true,才可以释放连接资源
- 然后,判断当前事务有没有挂起的连接,如果有,恢复挂起的连接
恢复挂起的连接就是重新建立当前线程和连接对象的绑定关系
finally {
cleanupAfterCompletion(status);
}
// ---------------------------------
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
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());
}
}