http://sishuok.com/forum/blogPost/list/2502.html数据库事务
http://sishuok.com/forum/blogPost/list/2506.html(不推荐)编程事务:两种,(重点了解)事务定义:隔离级别和传播行为等
http://sishuok.com/forum/blogPost/list/2508.html声明事务
Spring事务分为对一个数据库操作的事务(对JDBC事务的封装)和对多个数据库操作的分布式事务
本文讨论的都是声明式事务,首先看下Spring事务处理的设计类图:
从类图中可以发现,ProxyConfig就是在前面Spring Aop原理分析(一)提到的父类,不难发现,Spring声明式事务就是用Aop来实现的,我们重点分析以下几个类
通过以上信息,对整个事务的流程以及所使用到的类都很清楚,模仿着事务组件,也可以开发出我们自己的组件
该时序图已经很清楚说明了事务处理拦截器的配置(TransactionProxyFactoryBean.createMainInterceptor),具体来说,这里涉及的类是TransactionAttributeSourceAdvisor,它是一个Aop通知器,通过TransactionInterceptor为通知器设置拦截器
在声明式事务处理中,通过对目标对象的方法调用进行拦截实现,这个拦截通过Aop发挥作用。在Aop中,对于拦截的启动,首先需要对方法调用是否需要拦截进行判断,而判断的依据是那些在TransactionProxyFactoryBean中为目标对象设置的事务属性。也就是说,需要判断当前的目标方法调用是不是一个配置好的并且需要进行事务处理的方法调用。
以下代码是事务处理配置的读入的实现,配置的是一个NameMatchTransactionAttributeSource对象
TransactionProxyFactoryBean
public void setTransactionAttributes(Properties transactionAttributes) {
this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
}
在应用调用目标方法的时候,因为这个目标方法已经被TransactionProxyFactoryBean代理,所以TransactionProxyFactoryBean需要判断这个目标方法是否是事务方法,典型调用过程如图:
在完成以上的准备工作以后,经过TransactionProxyFactoryBean的Aop的包装,此时如果对目标对象进行方法调用,起作用的实际上是一个Proxy代理对象,对目标对象方法的调用,不会直接作用在TransactionProxyFactoryBean设置的目标对象上,而会被设置的事务拦截器拦截。TransactionProxyFactoryBean作为一个FactoryBean,对这个Bean的对象的引用是通过调用TransactionProxyFactoryBean .getObject方法来得到的,如果还有印象,大家会注意到一个重要的involve方法,这个invoke方法是Proxy代理对象的回调方法,即在事务处理拦截器TransactionInterceptor.invoke中,其过程是
下面是事务提交的时序图:
根据上一节事务提交的时序图可知,TransactionAspectSupport.createTransactionIfNecessary方法作为事务创建的入口,
再看createTransactionIfNecessary方法调用的时序图:
事务的隔离级别和传播行为都定义在该类TransactionDefinition中
在Spring中,AbstractPlatformTransactionManager.getTransaction是对事务隔离级别和传播行为的实现,细节就不再研究了,不同事务处理器例如DataSourceTransactionManager、JpaTransactionManager、DataSourceTransactionManager会处理不同的事务细节,包括事务的提交、事务的挂起、事务的回滚等
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
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 ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}