【推荐】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()方法调用。 在自己的类中注入自己,通过注入的自己调用,或者写在别的类中,注入别的类调用。
来源:oschina
链接:https://my.oschina.net/fusublog/blog/3155730