面试的时候遇到过这个问题,过后一脸懵逼。当初记录一下。。。
@Transactional生效场景
1. 在类外部调用调用类外部@Transactional标注的办法
1.1 定义一个谬误的@Transactional标注实现,设置一个外部调用
@Servicepublic 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
@Servicepublic 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)); }}
@Servicepublic 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 写一个外部捕获异样,且不再抛出新的异样的办法
@Servicepublic 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...