默认情况下Spring中事务@Transactional的简单理解
首先声明,此文建立在默认的配置下的总结,其它需要特别配置的文中会有说明
一、两个方法互相调用时事务如何传递?
Spring默认的事务传播行为都是:方法A调用方法B,如果已经开启了事务,B不会开启新的事务,用A同一个事务,如果没有事务,则会创建事务
二、在Controller层调用两个不同的Service层方法能保证事务吗?
答案是不能。在Controller层调用两个Service方法,默认会开启两个事务,一个事务异常不会引起另一个事务的回滚,除非在Controller层也定义事务,但是显然是不行的,所以Controller层禁止调用两个Service方法,业务逻辑一定放在Service层
三、如何在事务中开启子事务?外部事务回滚不影响子事务
三种方法:
- 开启新的session,手动开启、提交事务
//开启新的Session
Session session=SpringContextHolder.getBean(SessionFactory.class).openSession();
try {
session.beginTransaction(); //手动开启事务
xxxxxx //具体业务逻辑
session.getTransaction().commit(); //手动提交事务
} catch (Exception e) {
session.getTransaction().rollback() ;//手动回滚
throw e;
}finally{
session.close();
}
- 用@Transactional注解到方法上,同时设置事务传播行为为开启新的事务,propagation = Propagation.REQUIRES_NEW
//设置事务传播行为为:Propagation.REQUIRES_NEW
@Transatinal(propagation = Propagation.REQUIRES_NEW)
publi void save(User user){
xxxxxx;
}
- 使用编程式事务
//设置传播行为:总是新启一个事务,如果存在原事务,就挂起原事务transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.execute(new TransactionCallback<T>() {
@Override
public T doInTransaction(TransactionStatus arg0) {
//日志信息入库
save(log);
return null;
}
});
四、事务传播行为(propagation )的说明
-
REQUIRED:业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。
-
NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。
-
REQUIRESNEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
-
MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。
-
SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。
-
NEVER:该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。
-
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。