@Transactional详解

我是研究僧i 提交于 2020-01-10 10:59:26

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

看源码

public @interface Transactional {

	@AliasFor("transactionManager")
	String value() default "";

	@AliasFor("value")
	String transactionManager() default "";

	Propagation propagation() default Propagation.REQUIRED;

	Isolation isolation() default Isolation.DEFAULT;

	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

	boolean readOnly() default false;

	Class<? extends Throwable>[] rollbackFor() default {};

	String[] rollbackForClassName() default {};

	Class<? extends Throwable>[] noRollbackFor() default {};
	
	String[] noRollbackForClassName() default {};

}

transactionManager 和 value

这两个是别名关系,都是用来指定不同的事务管理器,主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1, txManager2.

然后,用户可以根据这个参数来根据需要指定特定的txManager.

比如在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的。

propagation

跟随测试代码一起理解事务传播机制:

测试事务类1

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

	@Autowired
	IStudentDao studentDao;

	@Autowired
	IBaseServiceB baseServiceb;

	@Transactional(propagation = 事务机制, 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(baseServiceb);
		System.out.println("是否是代理调用,AopUtils.isAopProxy(baseServiceb) : " + AopUtils.isAopProxy(baseServiceb));
		System.out
				.println("是否是cglib类代理调用,AopUtils.isCglibProxy(baseServiceb) : " + AopUtils.isCglibProxy(baseServiceb));
		System.out.println("是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(baseServiceb) : "
				+ AopUtils.isJdkDynamicProxy(baseServiceb));
		
		//使用代理调用方法doB()
		baseServiceb.doB();
		int i = 1 / 0;// 抛出异常,doB()的事务事务回滚
		return "success";
	}

}

测试事务类2

@Service("businessSerivceB")
public class BusinessServiceImplB implements IBaseServiceB {
 
	@Autowired
	IStudentDao studentDao;
	
	@Transactional(propagation = 事务机制,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";
	}
	 
}

测试主类

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) {
			e.printStackTrace();
		}
	}
	
}

Propagation事务传播机制

REQUIRED (默认)

A没有插入数据(被回滚),B也没有插入数据(也跟随A一起回滚)

A()执行时抛出了异常,因为B()和A()同属于一个事务,则执行操作被一起回滚了。

如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务。

SUPPORTS:

支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

MANDATORY:

支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

REQUIRES_NEW

数据库中插入了B方法的数据,而A方法中插入的数据被回滚了。

创建新事务,无论当前存不存在事务,都创建新事务。

NOT_SUPPORTED

B()方法成功插入了数据。A()方法中插入的数据被回滚了。

B()以非事务执行的,并且提交了。所以当A()的事务被回滚时,B()的操作没有被回滚。

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

NEVER:

以非事务方式执行,如果当前存在事务,则抛出异常。

NESTED:

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。内部事务回滚不会对外部事务造成影响, 它只对DataSourceTransactionManager 事务管理器起效.

@Trasation是怎么运作的

@Trasation的方法,使用aop形成事务增强advise。但是加入增强时是通过代理对象调用方法的形式加入的。如果将doB()方法放在doA()方法直接调用时,在同一个service中的方法调用,相当于是目标对象本身的this调用,并没有经过代理对象事务方法根本没有走,所以自然的事务配置的嵌套均无效。,只是相当于一个普通的方法调用而已,没有意义,这也就是为啥事务不让注解在私有方法或者protected上一样--矛盾且没意义。在Spring事务传播行为在内部方法不起作用讲到。

解决方法:

避免this.method()方法调用。 在自己的类中注入自己,通过注入的自己调用,或者写在别的类中,注入别的类调用。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!