@Transactional失效及事务传播特性
1、@Transactional注解失效
@Transactional注解不起作用的场景:
1、带有@Transactional注解的方法不是public方法
2、在同一个类中的非@Transactional方法调用了带有@Transactional注解的方法
3、在带有@Transactional注解的方法内部捕获了异常,但没有抛出新的异常
下面根据@Transactional的原理分析上述三种场景下为什么@Transactional不起作用。
1.1、非public方法
1、若带有@Transactional注解的方法不是public方法,则事务不起作用。
根据@Transactional的原理分析可知,在BeanFactoryTransactionAttributeSourceAdvisor类的getTransactionAttributeSource()方法中会调用computeTransactionAttribute方法来获取TransactionAttribute,在computeTransactionAttribute方法中进行了判断,默认只对public方法进行事务代理。如果不是public方法,则返回null,若TransactionAttribute是null,则认为方法上没有@Transactional注解。如下源码所示。
下面是 TransactionAttributeSourcePointcut 进行匹配的源码:
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
@Override
public boolean matches(Method method, @Nullable Class<?> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
//获取 BeanFactoryTransactionAttributeSourceAdvisor 中的AnnotationTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
//判断TransactionAttribute不为空,说明该targetClass的method是有事务注解的
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
}
调用AbstractFallbackTransactionAttributeSource的getTransactionAttribute方法:
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
//构建一个缓存key
Object cacheKey = getCacheKey(method, targetClass);
//从缓存中获取TransactionAttribute
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
//返回缓存中的TransactionAttribute
return cached;
}
}
else {
// We need to work it out.
//查找和解析method的事务注解,封装成TransactionAttribute
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
//把 TransactionAttribute 放入缓存attributeCache
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
看一下 computeTransactionAttribute 方法的源码:
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
//默认只能是public方法进行事务代理,但是可以通过allowPublicMethodsOnly方法修改
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
//有可能找到的是接口方法,但是需要的是实现类的方法
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
//【重要】首先从方法上找事务注解,有就返回,没有再找类上的事务注解,所以方法上的事务注解优先级高
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
//[重要]然后从当前类上找注解
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
//如果最终的目标方法和当前方法不一致,从当前方法上找
if (specificMethod != method) {
//回退是看原方法
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
//最后一个回退是原始方法的类
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
//实在找不到,返回一个null,该方法不会被代理
return null;
}
1.2、同类中方法调用
2、若在同一个类中的非@Transactional方法调用了带有@Transactional注解的方法,则事务不起作用
@Component
public class TestServiceImpl implements TestService {
@Resource
TestMapper testMapper;
//正常public修饰符的事务方法
@Transactional
public void methodA() {
int re = testMapper.insert(new Test(10,20,30));
if (re > 0) {
throw new RuntimeException("插入失败");
}
}
public void methodB(){
//类内部调用@Transactional标注的方法。
this.methodA();
}
}
由上述示例代码所示,由于methodB方法没有被@Transactional注解修饰,不会生成与该方法对应的拦截器,所以TransactionInterceptor不会对该方法进行事务处理。由于methodA方法带有@Transactional注解,所以AOP动态代理会为TestServiceImpl类生成一个代理对象,在代理对象中对methodA和methodB方法进行了重写。由JDK动态代理的原理可知,在这两个重写的方法内部分别调用了JdkDynamicAopProxy的invoke方法。JdkDynamicAopProxy的源码如下所示:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//创建代理
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//创建代理类
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//...省略其他代码...
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法调用
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//省略了其他代码
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
//目标类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//获取此方法的拦截器通知链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
//如果没有拦截器能应用到该方法,直接反射调用方法
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//创建 ReflectiveMethodInvocation 方法调用
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
//通过拦截器链进入连接点,调用增强方法
retVal = invocation.proceed();
}
//省略其他代码
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
invoke方法中首先获取方法的拦截器通知链,如果有就会创建 MethodInvocation来调用方法,应用通知,如果没有拦截器链就直接反射调用方法。所以在JdkDynamicAopProxy的invoke方法中通过反射直接调用目标类的methodB方法,并没有为该方法进行事务处理。
解决方法:为methodB方法添加@Transactional注解。
在同一个类中方法间的调用是通过this实现的,只是简单的方法调用,并未调用代理对象的methodA方法,methodB方法其实就是下面这种形式:
public void methodB(){
int re = testMapper.insert(new Test(10,20,30));
if (re > 0) {
throw new RuntimeException("插入失败");
}
}
所以另一种解决方法是:在TestServiceImpl中注入自己(实际是代理对象),通过代理对象调用methodA方法,如下所示:
@Autowired
Private TestServiceImpl testServiceImpl;
public void methodB(){
//类内部调用@Transactional标注的方法。
testServiceImpl.methodA();
}
1.3、方法内部捕获异常
3、在带有@Transactional注解的方法内部捕获了异常,但没有抛出新的异常
@Transactional
public void methodA() {
try{
int re = testMapper.insert(new Test(10,20,30));
if (re > 0) {
throw new RuntimeException("抛出异常");
}
} catch(Exception e){
System.out.println("插入失败");
}
}
如上所示,public方法methodA虽然被@Transactional注解修饰了,但是在该方法内部捕获了异常,且没有抛出新的异常。由事务原理可知,在TransactionInterceptor的invoke方法中,调用了父类TransactionAspectSupport的invokeWithinTransaction方法,该方法的源码如下所示:
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
/**
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
//获取事务属性源:即 @Transactional注解的属性
TransactionAttributeSource tas = getTransactionAttributeSource();
//获取事务属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//方法名,类名+方法名:如 cn.xx.UserServiceImpl.save
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
//声明式事务处理 @Transactional
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 【标记1】Standard transaction demarcation with getTransaction and commit/rollback calls.
//创建TransactionInfo事务详情对象,其中包括事务管理器(transactionManager),事务属性(transactionAttribute),方法名(joinpointIdentification),事务状态(transactionStatus)
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//【标记2】执行方法,这是一个环绕通知,通常会导致目标对象被调用
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
// target invocation exception
//回滚事务:AfterThrowing
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
//清理事务
cleanupTransactionInfo(txInfo);
}
//AfterReturning:后置通知,提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
//省略了其他代码
}
}
}
如果目标方法中抛出了异常,在invokeWithinTransaction方法中会捕获并回滚事务。但是如果目标方法自己处理了异常,在invokeWithinTransaction方法中就无法获取到异常,事务自然就无法回滚,就会正常提交。
1.4、未使用代理对象
如果没有使用代理对象,而是使用普通bean对象,也会导致@Transactional失效。
如下案例所示,有一个接口StatisticsHandler,该接口有两个实现类UserStatisticsHandler(用户数统计处理器)和FlowStatisticsHandler(流量统计处理器),分别用于统计用户数和流量数。基于策略模式,根据不同的统计类型执行相应的方法。
public interface StatisticsHandler {
/**
* 初始化 StatisticsHandlerHolder 类中的 Map
*/
void initMap();
/**
* 统计数量
*/
void statisticsCount();
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@Service
public class UserStatisticsHandler implements StatisticsHandler {
@Autowired
private StatisticsHandlerHolder statisticsHandlerHolder;
@Autowired
private ApplicationContext applicationContext;
/**
* 注意:此处的this是普通bean对象,如果通过this调用statisticsCount方法,会使得@Transactional不生效。
* 为了使事务生效,可以从spring容器中获取代理对象保存到holder容器中,从holder中获取的就是代理对象。
*/
@Override
@PostConstruct
public void initMap() {
// statisticsHandlerHolder.getHandlerMap().putIfAbsent(StatisticsTypeEnum.USER.name(), this);
statisticsHandlerHolder.getHandlerMap()
.putIfAbsent(StatisticsTypeEnum.USER.name(), applicationContext.getBean(UserStatisticsHandler.class));
}
@Override
@Transactional
public void statisticsCount() {
// todo
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class FlowStatisticsHandler implements StatisticsHandler {
@Autowired
private StatisticsHandlerHolder statisticsHandlerHolder;
@Autowired
private ApplicationContext applicationContext;
/**
* 注意:此处的this是普通bean对象,如果通过this调用statisticsCount方法,会使得@Transactional不生效。
* 为了使事务生效,可以从spring容器中获取代理对象保存到holder容器中,从holder中获取的就是代理对象。
*/
@Override
public void initMap() {
// statisticsHandlerHolder.getHandlerMap().putIfAbsent(StatisticsTypeEnum.FLOW.name(), this);
statisticsHandlerHolder.getHandlerMap()
.putIfAbsent(StatisticsTypeEnum.FLOW.name(), applicationContext.getBean(FlowStatisticsHandler.class));
}
@Override
@Transactional
public void statisticsCount() {
// todo
}
}
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Getter
@Setter
@Service
public class StatisticsHandlerHolder {
/**
* 用于维护统计类型与统计处理器的关系,key是统计类型
*/
private Map<String, StatisticsHandler> handlerMap = new ConcurrentHashMap<>();
/**
* 获取统计处理器
*
* @param type 统计类型
* @return 统计处理器
*/
public StatisticsHandler getStatisticsHandler(StatisticsTypeEnum type) {
return handlerMap.get(type.name());
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class StatisticsService {
@Autowired
private StatisticsHandlerHolder statisticsHandlerHolder;
public void statisticsCount(StatisticsTypeEnum type) {
StatisticsHandler statisticsHandler = statisticsHandlerHolder.getStatisticsHandler(type);
// 如果使用普通bean对象会导致事务失效,需要使用代理对象
statisticsHandler.statisticsCount();
}
}
public enum StatisticsTypeEnum {
USER,
FLOW
}
2、@Transactional不起作用的解决方法
pom.xml文件:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
启动类:
package com.tx.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @Author: 倚天照海
* @EnableTransactionManagement注解用于开启事务
* EnableAspectJAutoProxy(exposeProxy=true)表示开启AOP代理,通过spring管理带
* 有@Aspect注解的类的创建,暴露代理对象,通过aopContext能够访问代理对象
*/
@SpringBootApplication
@EnableTransactionManagement
@EnableAspectJAutoProxy(exposeProxy = true)
public class TxStudyApplication {
public static void main(String[] args) {
SpringApplication.run(TxStudyApplication.class,args);
}
}
Controller类:
package com.tx.study.controller;
import com.tx.study.pojo.OrderInfoDto;
import com.tx.study.service.TxService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: 倚天照海
*/
@RestController
@RequestMapping(value = "/tx")
public class TxController {
@Autowired
private TxService txService;
@PostMapping(value = "/order")
public void createOrderAndInfo(@RequestBody OrderInfoDto orderInfoDto){
txService.createOrderAndInfo(orderInfoDto);
}
}
Service类:
package com.tx.study.service;
import com.tx.study.dao.TxDao;
import com.tx.study.pojo.Order;
import com.tx.study.pojo.OrderInfo;
import com.tx.study.pojo.OrderInfoDto;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
/**
* @Author: 倚天照海
* 解决@Transactional注解不起作用的问题
*/
@Service
public class TxService {
@Autowired
private TxDao txDao;
//方式一:自己注入自己
@Autowired
private TxService txServiceProxy;
@Autowired
private ApplicationContext applicationContext;
public void createOrderAndInfo(OrderInfoDto orderInfoDto) {
//方式二:通过spring应用上下文获取bean实例
//TxService txServiceProxy = applicationContext.getBean(TxService.class);
//方式三:通过aspectj暴露代理对象,需要引入<groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId>依赖
//TxService txServiceProxy = (TxService) AopContext.currentProxy();
Order order = new Order();
order.setOrderId(orderInfoDto.getOrderId());
order.setUsername(orderInfoDto.getUsername());
order.setOrderTime(orderInfoDto.getOrderTime());
//保存订单数据
txServiceProxy.createOrder(order);
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderId(orderInfoDto.getOrderId());
orderInfo.setOrderName(orderInfoDto.getOrderName());
orderInfo.setGoods(orderInfoDto.getGoods());
orderInfo.setDescribe(orderInfoDto.getDescribe());
try {
//保存订单信息数据,如果出现异常,不能影响订单数据的保存
txServiceProxy.createOrderInfo(orderInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void createOrder(Order order){
String sql = "insert into t_order(order_id,username,order_time) values(?,?,?)";
if (ObjectUtils.isEmpty(order)){
return;
}
txDao.createOrder(sql,order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void createOrderInfo(OrderInfo orderInfo){
String sql = "insert into t_order_info(order_id,order_name,goods,order_describe) values(?,?,?,?)";
if (ObjectUtils.isEmpty(orderInfo)){
return;
}
txDao.createOrderInfo(sql,orderInfo);
//模拟异常
for (int i=1;i>=0;i--){
int num = 1/i;
}
}
}
Dao类:
package com.tx.study.dao;
import com.tx.study.pojo.Order;
import com.tx.study.pojo.OrderInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* @Author: 倚天照海
*/
@Repository
public class TxDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void createOrder(String sql, Order order){
String orderId = order.getOrderId();
String username = order.getUsername();
String orderTime = order.getOrderTime();
Object[] params = new Object[]{orderId,username,orderTime};
jdbcTemplate.update(sql,params);
}
public void createOrderInfo(String sql, OrderInfo orderInfo){
String orderId = orderInfo.getOrderId();
String orderName = orderInfo.getOrderName();
String goods = orderInfo.getGoods();
String describe = orderInfo.getDescribe();
Object[] params = new Object[]{orderId,orderName,goods,describe};
jdbcTemplate.update(sql,params);
}
}
由下图可知,this对象并不是代理对象,自动注入的txServiceProxy才是代理对象。
3、事务传播特性
事务传播特性或行为就是多个事务方法相互调用时,事务如何在这些方法间传播。
1.PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择,是spring默认的事务传播行为。
2.PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
3.PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作,即新建一个事务。
4.PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
5.PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
7.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
假设有两个方法:ServiceA.methodA和ServiceB.methodB,ServiceA和ServiceB是两个类,在ServiceA.methodA方法中调用ServiceB.methodB方法。
1、如果methodA方法没有事务,methodB方法的事务类型是PROPAGATION_REQUIRED,即方法上使用@Transactional(propagation=Propagation.REQUIRED)注解,则methodB方法会新建一个事务。
2、如果ServiceA.methodA方法的事务行为类型是PROPAGATION_REQUIRED,即方法上使用@Transactional(propagation=Propagation.REQUIRED)注解,ServiceB.methodB方法上也使用@Transactional(propagation=Propagation.REQUIRED)注解,则ServiceB.methodB方法不会新建事务,而是加入到ServiceA.methodA方法的事务中。并且这两个方法的事务会互相影响,也就是说,如果这两个方法中有一个方法中抛出异常,则这两个方法的事务都会回滚。即使在ServiceA.methodA方法中调用ServiceB.methodB方法的地方使用try…catch捕获处理,如果ServiceB.methodB方法中抛出异常,则这两个方法的事务都会回滚。
3、如果ServiceA.methodA方法上使用@Transactional(propagation=Propagation.REQUIRED),ServiceB.methodB方法上使用@Transactional(propagation=Propagation.REQUIRES_NEW),则ServiceB.methodB方法会新建一个事务,并将ServiceA.methodA方法的事务挂起。并且ServiceB.methodB方法的事务会影响ServiceA.methodA方法的事务,而ServiceA.methodA方法的事务不会影响ServiceB.methodB方法的事务,也就是说,如果ServiceB.methodB方法中抛出了异常,则ServiceB.methodB方法的事务会回滚,如果在ServiceA.methodA方法中调用ServiceB.methodB方法的地方没有使用try…catch捕获处理,则ServiceA.methodA方法的事务也会回滚,这相当于在ServiceA.methodA方法中也抛出了异常。如果ServiceA.methodA方法中抛出了异常,而ServiceB.methodB方法中没有抛出异常,则ServiceA.methodA方法的事务会回滚,而ServiceB.methodB方法的事务可以正常提交。
4、如果ServiceA.methodA方法上使用@Transactional(propagation=Propagation.REQUIRED),ServiceB.methodB方法上使用@Transactional(propagation=Propagation.NESTED),则methodB方法的事务嵌套在methodA方法的事务内执行,并且methodA方法的事务会影响methodB方法的事务,而methodB方法的事务不一定会影响methodA方法的事务,需要根据在methodA方法中是否使用try…catch捕获处理methodB方法来进行判断。如果methodB方法抛出异常,并且在methodA方法中调用methodB方法的地方使用try…catch捕获处理,则methodB方法的事务会回滚,methodA方法的事务不会回滚,而是正常提交。如果在methodA方法中调用methodB方法的地方没有使用try…catch捕获处理,则methodA方法的事务也会回滚。如果methodB方法没有抛出异常,而methodA方法抛出异常,则这两个方法的事务都会回滚。Propagation.NESTED事务的提交要等待与其外层父事务一起提交。
5、如果methodA方法有事务,methodB方法没有事务,methodA方法调用methodB方法,无论这两个方法是否在同一个类中, 都只会共用一个事务,要么都提交,要么都回滚。