之前面试时问到这个问题,明明以前学习过但是基本都忘记了,在此记录(文章部分内容参考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必须手动修改配置开启事务。

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

被折叠的 条评论
为什么被折叠?



