spring 事务原理
统观spring事务,围绕着两个核心PlatformTransactionManager和TransactionStatus?
spring提供了几个关于事务处理的类:?
TransactionDefinition //事务属性定义?
TranscationStatus //代表了当前的事务,可以提交,回滚。?
PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。?
一般事务定义步骤:?
TransactionDefinition td = new TransactionDefinition();?
TransactionStatus ts = transactionManager.getTransaction(td);?
try?
{ //do sth?
? transactionManager.commit(ts);?
}?
catch(Exception e){transactionManager.rollback(ts);}?
spring提供的事务管理可以分为两类:编程式的和声明式的。编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活。?
编程式主要使用transactionTemplate。省略了部分的提交,回滚,一系列的事务对象定义,需注入事务管理对象.?
void add()?
{?
??? transactionTemplate.execute( new TransactionCallback(){?
??????? pulic Object doInTransaction(TransactionStatus ts)?
?????? { //do sth}?
??? }?
}?
声明式:?
使用TransactionProxyFactoryBean:?
<bean id="userManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">?
? <property name="transactionManager"><ref bean="transactionManager"/></property>?
? <property name="target"><ref local="userManagerTarget"/></property>?
? <property name="transactionAttributes">?
?? <props>?
??? <prop key="insert*">PROPAGATION_REQUIRED</prop>?
??? <prop key="update*">PROPAGATION_REQUIRED</prop>?
??? <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>?
?? </props>?
? </property>?
</bean>?
围绕Poxy的动态代理 能够自动的提交和回滚事务?
org.springframework.transaction.interceptor.TransactionProxyFactoryBean?
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。?
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。?
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。?
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。?
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。?
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。?
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。?
Spring 事务管理创造性的解决了很多以前要用重量级的应用服务器才能解决的事务问题,那么其实现原理一定很深奥吧?可是如果读者仔细研究了Spring事务管理的代码以后就会发现,事务管理其实也是如此简单的事情。这也印证了在本书开头的一句话“重剑无锋、大巧不工”,Spring并没有使用什么特殊的API,它运行的原理就是事务的原理。下面是DataSourceTransactionManager的启动事务用的代码(经简化):?
protected void doBegin(Object transaction, TransactionDefinition definition)?
{?
DataSourceTransactionObject txObject =?
(DataSourceTransactionObject) transaction;?
Connection con = null;?
try?
{?
? if (txObject.getConnectionHolder() == null)?
? {?
?? Connection newCon = this.dataSource.getConnection();?
?? txObject.setConnectionHolder(?
new ConnectionHolder(newCon), true);?
? }?
? txObject.getConnectionHolder()?
.setSynchronizedWithTransaction(true);?
? con = txObject.getConnectionHolder().getConnection();?
? Integer previousIsolationLevel = DataSourceUtils?
???? .prepareConnectionForTransaction(con, definition);?
? txObject.setPreviousIsolationLevel(previousIsolationLevel);?
? if (con.getAutoCommit())?
? {?
?? txObject.setMustRestoreAutoCommit(true);?
?? con.setAutoCommit(false);?
? }?
? txObject.getConnectionHolder().setTransactionActive(true);?
? // Bind the session holder to the thread.?
? if (txObject.isNewConnectionHolder())?
? {?
?? TransactionSynchronizationManager.bindResource(?
getDataSource(),txObject.getConnectionHolder());?
? }?
}?
catch (SQLException ex)?
{?
? DataSourceUtils.releaseConnection(con, this.dataSource);?
? throw new CannotCreateTransactionException(?
???? "Could not open JDBC Connection for transaction", ex);?
}?
}?
本文出自:http://www.cownew.com?
在调用一个需要事务的组件的时候,管理器首先判断当前调用(即当前线程)有没有一个事务,如果没有事务则启动一个事务,并把事务与当前线程绑定。Spring使用TransactionSynchronizationManager的bindResource方法将当前线程与一个事务绑定,采用的方式就是ThreadLocal,这可以从TransactionSynchronizationManager类的代码看出。?
public abstract class TransactionSynchronizationManager?
{?
……?
private static final ThreadLocal currentTransactionName = new ThreadLocal();?
private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();?
private static final ThreadLocal actualTransactionActive = new ThreadLocal(); ……?
}?
从doBegin的代码中可以看到在启动事务的时候,如果Connection是的自动提交的(也就是getAutoCommit()方法返回true)则事务管理就会失效,所以首先要调用setAutoCommit(false)方法将其改为非自动提交的。setAutoCommit(false)这个动作在有的JDBC驱动中会非常耗时,所以最好在配置数据源的时候就将“autoCommit”属性配置为true。?
首先,为什么要进行事务,接下来说说spring是怎样进行事务管理的.?
① Spring事务策略?
Spring事务策略,也就是spring事务管理的实现方式.它有一个统一的抽象是由实现下面这个接口完成的.?
org.springframework.transaction.PlatformTransactionManager?
此接口的内容如下:?
Public interfacePlatformTransactionManager()...{?
TransactionStatue getTransaction(TransactionDefinition definition) throws TransactionException;?
Void commit(TransactionStatus status) throws TransactionException;?
Void rollback(TransactionStatus status) throws TransactionException;?
}?
不管是声明式的还是编程式的事务管理都需要此抽象来完成.?
解释一下这个接口,这样可以更好的理解spring的事务控制的原理.?
getTransaction()根据类型为TransactionDefinition的参数返回一个TransactionStatus对象.返回的TransactionStatus对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务).如同J2EE事务上下文,一个TransactionStatus也是和执行的线程关联的.?
同时,在框架中还存在TransactionDefinition接口,即上边的参数类型.此接口指定了事务隔离程度、事务传播、事务超时、只读状态。
另外,还有TransactionStatus接口。这个接口为处理事务提供简单的控制事务执行和查询事务状态的方法。?
② 两种事务管理方式:编程式、声明式。?
Spring提供两种方式的编程式事务管理,分别是:使用TransactionTemplate和直接使用PlatformTransactionManager。?
ⅰ. TransactionTempale采用和其他Spring模板,如JdbcTempalte和HibernateTemplate一样的方法。它使用回调方法,把应用程序从处理取得和释放资源中解脱出来。如同其他模板,TransactionTemplate是线程安全的。?
代码片段:?
Object result =tt.execute(newTransactionCallback()...{?
publicObject doTransaction(TransactionStatus status)...{?
updateOperation();?
returnresultOfUpdateOperation();?
}?
});?
使用TransactionCallback()可以返回一个值。?
如果使用TransactionCallbackWithoutResult则没有返回值。?
ⅱ. 也可以使用PlatformTransactionManager直接管理事务。简单地通过一个bean引用给你的bean传递一个你使用的PlatformTransaction对象。然后,使用TransactionDefinition和TransactionStatus对象就可以发起、回滚、提交事务。?
如下片段:?
DefaultTransactionDefinition def=newDefaultTransactionDefinition(); //new 一个事务?
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //初始化事务,参数定义事务的传播类型;?
TransactionStatus status =transactionManager.getTransaction(def); //获得事务状态?
try...{?
……………..?
transactionManager.commit(status); //提交事务;?
}catch(…..)...{?
transactionManager.rollback(status); //回滚事务;?
}?
Spring也提供声明式事务管理。这是通过AOP实现的。?
大多数Spring用户选择声明式事务管理,这是最少影响应用代码的选择,因而这是和非侵入性的轻量级容器的观念是一致的。?
① 通常通过TransactionProxyFactoryBean设置Spring事务代理。需要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Javabean。当我们定义TransactionProxyFactoryBean时,必须提供一个相关的PlatformTransactionManager的引用和事务属性。事务属性含有事务定义。例如:?
PROPAGATION_REQUIRED,-MyCheckedException?
PROPAGATION_REQUIRED?
PROPAGATION_REQUIRED,readOnly?
事务代理会实现目标对象的接口:这里是属性名是target的引用。id是transactionServiceControl。(●使用CGLIB也可以实现具体类的代理。只要设置proxyTargetClass属性为true即可。如果目标对象没有实现任何接口,这将自动设置该属性为true。通常,我们希望面向接口编程。) ●使用proxyInterfaces属性来限定事务代理来代理指定接口也是可以。 ●也可以通过从org.springframework.aop.framework.ProxyConfig继承或所有AOP代理工厂共享的属性来定制TransactionProxyFactoryBean行为。?
然后,说说属性名是transactionAttributes意义:?
这里的transactionAttributes属性是定义在org.springframework.transaction.interceptor.NameMathTransactionAttributeSource中的属性格式设置。这个包括通配符的方法名称映射是很直观的,如”insert*”。注意insert*的映射的值包括回滚规则。”-MyCheckException”指定如果方法抛出MyCheckException或它的子类,事务会自动回滚。可以用逗号分隔多个回滚规则。“-”前缀强制回滚,“+”前缀指定提交(这允许即使抛出unchecked异常时也可以提交事务)。“PROPAGATION_REQUIRED”指定事务传播范围。?
TransactionProxyFactoryBean允许你通过“preInterceptors”和“postInterceptors”属性设置前或后的拦截操作。可以设置任意数量的前和后通过,它们的类型可以是Advistor(切入点),MethodInterceptor或被当前Spring配置支持的通知类型。例如:ThrowAdvice,AfterReturningAdvice或BeforeAdvice。这些通知必须支持实例共享模式。如果你需要高级AOP特性操作事务,通过org.springframework.aop.framework.ProxyFactoryBean,而不是TransactionProxyFactory实用代理创建者。?
② 另一种声明方式:BeanNameAutoProxyCreator?
使用TransactionProxyFactoryBean当事务代理包装对象,你可以完全控制代理。如果需要用一致方式包装大量bean。使用一个BeanFactoryPostProcessor的一个实现,BeanNameAutoProxyCreator,可以提供另外一种方法。(Spring中,一旦ApplicationContext读完它的初始化信息,它将初始化所有实现BeanPostProcessor接口的bean,并且让它们后处理ApplicationContext中所有其他的bean。所以使用这种机制,正确配置的BeanNameAutoProxyCreator可以用来后处理所有ApplicationContext中所有其他的bean),并且把它们用事务代理包装起来。真正生成的事务代理和使用TransactionProxyFactoryBean生成的基本一致。?
Spring的事务管理的大致实现如下:?
关键类和方法:?
org.springframework.transaction.interceptor.TransactionInterceptor.invoke?
org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary?
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction?
事务管理只有一个interceptor,那就是TransactionInterceptor。它在对象调用的每个方法之前都会检查一下是否有必要新建一个transaction?
createTransactionIfNecessary用来检查是否有必要新建一个transaction。?
步骤如下:?
寻找transactionAttributes中是否定义有匹配的方法名,匹配包括完全匹配和正则匹配.(优先寻找完全匹配)?
1。如果发现定义中有匹配的定义,则?
2。从ThreadLocal中找到connectionHoler对象,该对象是在DataSourceUtil.getConnection(DataSource)中获得的。这就是为什么要使用DataSourceUtil.getConnection(DataSource)?
的原因。一个connectionHolder对象里边记录了被请求的次数。?
3。检查当前的Transaction是否存在?即查找ThreadLocal里边的connectionHolder是否存在,如果存在,表示Transaction已经存在,直接返回。?
4。如果当前的Transaction在ThreadLocal中不存在,那么调用DataSourceTransactionManager.doBegin()方法。来新建一个transaction.