Spring事务失效场景总结

本文总结了Spring事务管理可能失效的九种情况,包括方法访问修饰符不当、方法被final或static修饰、内部直接调用方法、多线程调用、Bean未被Spring管理等,并针对每种情况给出了相应的解决方案。

之前面试时问到这个问题,明明以前学习过但是基本都忘记了,在此记录(文章部分内容参考IT老哥B站视频)。

1、事务方法的访问修饰符非public

Java访问权限修饰符共有:private、default、protected、public,Spring中,仅被public修饰的方法事务才会生效,如果方法被错误的访问权限修饰符修饰,事务不生效。

@Service
public class UserService {
    @Transactional
    private void add(UserModel userModel) {
         saveData(userModel);
    }
}

2、方法被final或static所修饰

Spring中事务管理使用了动态代理机制,如果方法被final和static关键字修饰,则无法重写,也就无法被代理,所以事务不生效。

@Service
public class UserService {
    @Transactional
    public final void add(UserModel userModel) {
         saveData(userModel);
    }
    @Transactional
    public static void update(UserModel userModel) {
         updateData(userModel);
    }
}

3、在类的内部直接调用方法

Spring中事务管理使用了动态代理机制,在类的内部,直接调用成员方法不会调用动态代理方法,所以事物不会生效。

@Service
public class UserService {
    
    public void add(UserModel userModel) {
         saveData(userModel);
    }
    @Transactional
    public void saveData(UserModel userModel) {
        //一系列操作...
    }
}

当然,如果在add方法上也加入 @Transactional注解,事务即可生效,但此时生效的事务为add方法的事务。

或者直接在类中注入自己,也可以让事物生效,并且Spring处理了循坏依赖问题,并不会导致报错。

@Service
public class UserService {
    
    @Autowired
    private UserService userService;
	
    public void add(UserModel userModel) {
         userService.saveData(userModel);
    }
    @Transactional
    public void saveData(UserModel userModel) {
        //一系列操作...
        //此时事务管理会生效
    }
}

4、多线程调用方法

启用多线程后同时操作数据库,会导致同时创建多个数据库连接,事务是依赖数据库连接的,多个数据库连接会导致同时开启多个事务,所以会导致事务管理回滚失败。

@Service
public class UserService {
 
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleService roleService;
 
    @Transactional
    public void add(UserModel userModel) throws Exception {
        userMapper.insertUser(userModel);
        new Thread(() -> {
            roleService.doOtherThing();
        }).start();
    }
}
 
@Service
public class RoleService {
 
    @Transactional
    public void doOtherThing() {
        System.out.println("保存role表数据");
    }
}

5、事务方法所在的类必须由Spring管理

Spring无法获取Bean,也就无法代理,事务不生效。

//@Service 被注释
public class UserService {
    @Transactional
    private void add(UserModel userModel) {
         saveData(userModel);
    }
}

6、异常被手动处理

必须由Spring自动处理或统一处理的异常才会被事务回滚,使用try/catch手动处理的异常不会回滚。

情景一:update方法没有异常处理,发生异常不会导致add方法回滚

@Service
public class UserService {
    @Transactional
    private void add(UserModel userModel) {
         saveData(userModel);
          try {
             updateData(userModel);
             //此处出发的异常已经被手动处理,不会回滚
        } catch (Exception e) {
        }
    }
}

情景二:update方法需要异常处理,发生异常只会导致uodate方法回滚,不会导致add方法回滚

@Service
public class UserService {
    
    @Autowired
    private UserService userService;
    
	 @Transactional
    public void add(UserModel userModel) {
         saveData(userModel);
          try {
             userService.updateData(userModel);
             //此处出发的异常已经被手动处理,不会回滚,但
        } catch (Exception e) {
        }
    }
    @Transactional
    public void updateData(UserModel userModel) {
        //一系列操作...
        //此时事务管理会生效
    }
}

7、使用了自定义的异常回滚处理

Spring可以自定义处理那种异常,如果定义错误,则不处理。

@Service
public class UserService {
   
    @Transactional(rollbackFor = BusinessException.class)
    private void add(UserModel userModel) {
         saveData(userModel);
         throw new OtherException();
    }
}

8、使用的数据表类型不支持事务

老版本的MySQL数据库会将myisam作为默认表类型,但是此类型并不支持事务管理,所以即使Spring工程代码无任何错误,数据依旧无法回滚。

9、未开启事务管理

SpringBoot框架自动开启事务管理,但Spring必须手动修改配置开启事务。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值