Spring传播行为内部方法不起作用

在使用Spring的注解事务时候,我们发现内部方法声明的事务不起作用,而是决定于外部方法注解的事务。到底是真不起作用,还是我们Spring的事务注解机制理解错了,导致误用了。下面我们看两个例子:


测试类:

package com.aop;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.thread.service.IBaseFacadeService;


//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = { "classpath:/spring-ibatis.xml", "classpath:/spring-jdbctemplate.xml" })
public class TestStudentDao {

	public static void main(String[] args) {
		  try {
		  BeanFactory factory = new ClassPathXmlApplicationContext("spring-jdbctemplate.xml");
		  IBaseService service = (IBaseService) factory.getBean("businessSerivce");
		
			  service.doA();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

第一例子:内部方法事务不起作用:

package com.aop;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.entity.Student;

@Service("businessSerivce")
public class BusinessServiceImpl implements IBaseService {

	@Autowired
	IStudentDao studentDao;

	@Override
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
	public String doA() throws Exception {
		Student st = new Student();
		st.setId(1);
		st.setSex("girl");
		st.setUsername("zx");
		studentDao.insertStudent(st);

		System.out.println(this);
		System.out.println("是否是代理调用,AopUtils.isAopProxy(this) : " + AopUtils.isAopProxy(this));
		System.out.println("是否是cglib类代理调用,AopUtils.isCglibProxy(this) : " + AopUtils.isCglibProxy(this));
		System.out.println("是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(this) : " + AopUtils.isJdkDynamicProxy(this));

		this.doB();
		int i = 1 / 0;// 抛出异常,doB()的事务事务回滚
		return "success";
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
	public String doB() throws Exception {
		Student st = new Student();
		st.setId(2);
		st.setSex("girl");
		st.setUsername("zx2");
		studentDao.insertStudent(st);

		return "success";
	}

}
测试类执行结果:

com.aop.BusinessServiceImpl@5a47cf7
是否是代理调用,AopUtils.isAopProxy(this) : false
是否是cglib类代理调用,AopUtils.isCglibProxy(this) : false
是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(this) : false
java.lang.ArithmeticException: / by zero



从测试类执行结果可以看到,我们没有成功插入数据。理论来说方法doB()使用Propagation.REQUIRES_NEW传播行为,我们应该在数据库中插入姓名为zx2的数据,但是却是事与愿违,程序没有按照我们想要的方向走,不急,我们再看下面的例子:

第二例子:内部方法事务起作用

package com.aop;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.entity.Student;

@Service("businessSerivce")
public class BusinessServiceImpl implements IBaseService,ApplicationContextAware {

	@Autowired
	IStudentDao studentDao;
	
	@Autowired
	ApplicationContext context;
	

	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
	public String doA() throws Exception {
		Student st = new Student();
		st.setId(1);
		st.setSex("girl");
		st.setUsername("zx");
		studentDao.insertStudent(st);
		//BusinessServiceImpl service1 = (BusinessServiceImpl)context.getBean(IBaseService.class);
		BusinessServiceImpl service = (BusinessServiceImpl)context.getBean("businessSerivce");
		//System.out.println(service1);
		System.out.println(service);
		System.out.println("是否是代理调用,AopUtils.isAopProxy(service) : " + AopUtils.isAopProxy(service));
		System.out
				.println("是否是cglib类代理调用,AopUtils.isCglibProxy(service) : " + AopUtils.isCglibProxy(service));
		System.out.println("是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(service) : "
				+ AopUtils.isJdkDynamicProxy(service));

		// 使用代理调用方法doB()
		service.doB();
		
		int i = 1 / 0;// 抛出异常,doB()的事务事务回滚
		return "success";
	}
	

	@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
	public String doB() throws Exception {
		Student st = new Student();
		st.setId(2);
		st.setSex("girl");
		st.setUsername("zx2");
		studentDao.insertStudent(st);

		return "success";
	}


	@Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		context = arg0;
		
	}

}
测试类执行结果:

com.aop.BusinessServiceImpl@7b619bbf
是否是代理调用,AopUtils.isAopProxy(service) : true
是否是cglib类代理调用,AopUtils.isCglibProxy(service) : true
是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(service) : false
java.lang.ArithmeticException: / by zero

从执行结果来看,数据库中插入了一条数据,而这也正是我们想要的结果,数据库中插入的是doB()方法执行的结果,doA()执行结果被回滚了。


例一和例二有什么区别吗?我们来看打印出来的日志,例一中打印出调用doB()方法的对象this不是代理对象,而是代理目标对象。而例二调用doB()方法的对象service是代理对象,不是代理目标对象。最后例一没有我们达到我们的目的,而例二达到了我们目的。为什么代理目标对象执行doB()方法,声明在自己上面的事务就失效了,而代理对象执行doB()方法就成功了呢?这是因为spring在扫描所有类中@Transaction标记的方法的所有类,是通过代理对象植入事务这个特殊的前置增强(advise)的,而不是在代理目标对象上植入增强(advise)的。所以最后就出现了我们上面的两种结果。


注意我们这里使用的是Cglib动态代理(类代理)


所以我们在类BusinessServiceImpl中强制转换使用类强制转换

BusinessServiceImpl service = (BusinessServiceImpl)context.getBean("businessSerivce");
但是如果我们使用jdk动态代理 <aop:aspectj-autoproxy proxy-target-class=false/>

那我们就得使用接口强制转换:

IBaseService service = (IBaseService)context.getBean("businessSerivce");




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值