面试的时候遇到过这个问题,过后一脸懵逼。当初记录一下。。。
@Transactional 生效场景
1. 在类外部调用调用类外部 @Transactional 标注的办法
1.1 定义一个谬误的 @Transactional 标注实现,设置一个外部调用
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Resource
UserMapper userMapper;
@Override
public void oneTest() {oneTestNoPublic();
}
@Transactional(rollbackFor = Exception.class)
public void oneTestNoPublic(){
// 插入一条数据
int num = userMapper.insert(new User("小红", "青岛市", 18));
if (num > 0){
// 插入后制作一个谬误
System.out.println(1 / 0);
}
// 再次插入一条数据
userMapper.insert(new User("小强", "烟台市", 21));
}
}
1.2 测试用例
@RestController
@RequestMapping("/transactional")
public class TransactionalTestController {
@Resource
IUserService userService;
/**
* 在类外部调用调用类外部 @Transactional 标注的办法
*/
@GetMapping("/one")
public void oneTest(){
try {userService.oneTest();
} catch (Exception e){e.printStackTrace();
}
}
}
1.3 运行后,控制台报错:
1.4 查看数据库,发现并没有回滚 new User(“ 小红 ”, “ 青岛市 ”, 18) 这条数据
调用一个办法在类外部调用外部被 @Transactional 标注的事务办法,运行后果是事务不会失常开启。userMapper.insert(new User(“ 小红 ”, “ 青岛市 ”, 18)) 操作没有进行回滚。
2. @Transactional 注解标注办法修饰符为非 public
2.1 新写一个 TestServiceImpl,将 @Transactional 注解标注办法修饰符为非 public
@Service
public class TestServiceImpl {
@Resource
UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
void twoTestNoPublic(){
// 插入一条数据
int num = userMapper.insert(new User("小红", "青岛市", 18));
if (num > 0){
// 插入后制作一个谬误
System.out.println(1 / 0);
}
// 再次插入一条数据
userMapper.insert(new User("小强", "烟台市", 21));
}
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Resource
TwoTestServiceImpl twoTestService;
@Override
public void twoTest() {twoTestService.twoTestNoPublic();
}
}
2.2 测试用例
@RestController
@RequestMapping("/transactional")
public class TransactionalTestController {
@Resource
IUserService userService;
/**
* @Transactional 注解标注办法修饰符为非 public
*/
@GetMapping("/two")
public void twoTest(){
try {userService.twoTest();
} catch (Exception e){e.printStackTrace();
}
}
}
2.3 运行后,控制台报错:
2.4 查看数据库,发现并没有回滚 new User(“ 小红 ”, “ 青岛市 ”, 18) 这条数据
以上的拜访形式,导致事务没开启,因而在办法抛出异样时,userMapper.insert(new User(“ 小红 ”, “ 青岛市 ”, 18)) 操作没有进行回滚。如果 oneTestNoPublic() 办法改为 public 的话将会失常开启事务,userMapper.insert(new User(“ 小红 ”, “ 青岛市 ”, 18)) 将会进行回滚。
3. 事务办法外部捕获了异样,且没有抛出新的异样
3.1 写一个外部捕获异样,且不再抛出新的异样的办法
@Service
public class TestServiceImpl {
@Resource
UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public void threeTestNoPublic(){
// 插入一条数据
int num = userMapper.insert(new User("小红", "青岛市", 18));
if (num > 0){
try {
// 插入后制作一个谬误
System.out.println(1 / 0);
} catch (Exception e) {e.printStackTrace();
return;
}
}
// 再次插入一条数据
userMapper.insert(new User("小强", "烟台市", 21));
}
}
3.2 测试用例
@RestController
@RequestMapping("/transactional")
public class TransactionalTestController {
@Resource
IUserService userService;
/**
* 事务办法外部捕获了异样,且没有抛出新的异样
*/
@GetMapping("/three")
public void threeTest(){
try {userService.threeTest();
} catch (Exception e){e.printStackTrace();
}
}
}
3.3 运行后,控制台报错:
3.4 查看数据库,发现并没有回滚 new User(“ 小红 ”, “ 青岛市 ”, 18) 这条数据
如果须要在 catch 外面回滚数据的话,就须要抛出新的异样或者在 catch 外面应用如下代码:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
好了,下面三种就是 @Transactional 注解不起作用,@Transactional 注解生效的次要起因。
集体博客地址:
http://www.zhouzhaodong.xyz/
测试代码地址:
https://gitee.com/zhouzhaodon…