Spring事务处理-编程式事务和声明式事务

Spring框架提供编程式事务处理和声明式事务处理。
编程式事务处理就是指在业务代码中利用Spring框架提供的一些类进行事务处理。
声明式事务处理就是指在xml配置文件或注解的方式声明对某个类方法进行事务处理。
通过以上的描述可以大概知道编程式事务处理是以侵入的方式完成,代码的耦合度高一些。而声明式事务处理耦合度低,或者说基本没有耦合。

编程式事务管理是基于Spring框架底层的 API来完成的,在Spring中事务处理相关的有PlatformTransactionManager、TransactionDefinition 和 TransactionStatus 三个核心接口,其中PlatformTransactionManager是一个事务管理器接口,负责进行事务的提交和回滚等操作;TransactionDefinition是一个事务属性接口,用于定义事务相关的属性,包括事务的隔离属性,事务的传播属性,超时等等。TransactionStatus是一个事务接口,用于表示一个事务。编程式事务管理示例代码如下:

public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionDefinition txDefinition;
private PlatformTransactionManager txManager;
......
public boolean transfer(Long fromId, Long toId, double amount) {
TransactionStatus txStatus = txManager.getTransaction(txDefinition);
boolean result = false;
try {
result = bankDao.transfer(fromId, toId, amount);
txManager.commit(txStatus);
} catch (Exception e) {
result = false;
txManager.rollback(txStatus);
System.out.println("Transfer Error!");
}
return result;
}
}


在上面的代码中,模拟了一个转账操作,转账操作需要放在一个事务中进行。可以看到事务处理代码混杂在业务代码中。而且实际上,所有的事务处理操作都是上面的流程,所以Spring框架提供了一个类TransactionTemplate 。
示例如下:

 

public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionTemplate transactionTemplate;
......
public boolean transfer(final Long fromId, final Long toId, final double amount) {
return (Boolean) transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus status) {
Object result;
try {
result = bankDao.transfer(fromId, toId, amount);
} catch (Exception e) {
status.setRollbackOnly();
result = false;
System.out.println("Transfer Error!");
}
return result;
}
});
}
}


可以看到代码中不再包含对事务的创建提交等等步骤,在Spring框架中,随处可见这种消除样板代码的手段:模板方法模式+回调模式。来看下:

 

interface TransactionCallback{
	public void operateInTranasaction();
}
class TransactionTemplate{
	public void operateWithTransaction(TransactionCallback transactionCallback){
		beginTransaction();
		transactionCallback.operateInTranasaction();
		afterTransaction();
	}
	private void beginTransaction(){
		System.out.println("开始事务");
	}
	private void afterTransaction(){
		System.out.println("结束事务");
	}
	private TransactionTemplate(){}
	
	private static TransactionTemplate tt=new TransactionTemplate();
	public static TransactionTemplate getInstance(){
		return tt;
	}
}

public class Demo {
	public static void main(String [] args){
		TransactionTemplate.getInstance().operateWithTransaction(new TransactionCallback() {
			@Override
			public void operateInTranasaction() {
				// TODO Auto-generated method stub
				System.out.println("转账");
			}
		});
	}
}


对于事务操作这件事情,流程都是一样的,先开始事务,执行操作再结束事务。不同的是每个业务执行的操作是不一样的。我们将那些一样的步骤写成模板方法放到模板类中,不一样的方法留给子类重写,这样就可以实现代码的复用了,这是模板方法模式。对于一个类,他的某个方法传入一个接口,然后我们为这个方法传入这个接口的一种实现,这是回调模式。瞧上面的代码。

尽管在编程式事务当中利用一些设计模式可以消除样板式代码,但是他仍然无法消除业务代码和Spring框架相关类的耦合。而声明式事务处理可以实现解耦合。Spring的声明式事务处理是通过AOP实现的,AOP是面向切面编程,他用于对已经存在的代码进行增强是处理,其中涉及几个概念:
切面需要做的增强处理
切点增强处理的地点
通知增强处理的内容以及时间(方法前,方法后等等)
织入将增强处理和源代码重组后的代码

有了上面的概念,大家一定很好奇Spring是如何实现将切面织入进原来的代码的,这里需要了解动态代理模式。

在JAVA中,有动态代理模式和静态代理模式,静态代理模式就是在原有类的基础上做一个包装类,在此不再多说。重点说动态代理模式:动态代理模式是JAVA语言.(详细参见http://yizhenn.iteye.com/blog/2293092)

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class Demo {
	public static void main(String [] args){
		IOperation iOperation=(IOperation) new TransactionProxy().bind(new OperationImpl());
		iOperation.zhuanZhang();
	}
}

interface IOperation{
	public void zhuanZhang();
}
class OperationImpl implements IOperation{
	@Override
	public void zhuanZhang() {
		// TODO Auto-generated method stub
		System.out.println("转账");
	}
}

class TransactionProxy implements InvocationHandler{
	private Object originalObj;
	public Object bind(Object obj){
		this.originalObj=obj;
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
				obj.getClass().getInterfaces(), this);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result=null;
		result=method.invoke(originalObj, args);
		System.out.println("提交事务");
		return result;
	}
	
}


瞧,业务代码还是原来的模样,只是我们悄悄的生成了一个代理类。下面我们以最原始的配置方案为例讲解一下Spring利用AOP实现声明式事务操作的过程。

 

<beans...>
......
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"/>
</list>
</property>
</bean>
......
</beans>


首先Spring在xml文件中声明一个拦截器,拦截器负责拦截需要进行事务处理的方法,并为该类方法生成一个动态代理类,在动态代理类中织入相关事务操作。可以看到配置中为BankServiceImpl创建的代理类bankService。程序中在调用bankService的transfer方法时,会被拦截,然后转换成调用代理类的相关方法。这样就实现了以无耦合的方式进行的事务增强。

 

部分参考http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/

 

 

 

笔者开设了一个知乎live,详细的介绍的JAVA从入门到精通该如何学,学什么?

想深入学习和提高JAVA能力的同学,欢迎收听https://www.zhihu.com/lives/932192204248682496

提供给想学习云计算的同学,欢迎收听https://www.zhihu.com/lives/1046567982750281728

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值