@Transactional 手动数据回滚 No transaction aspect-managed TransactionStatus in scope ; Transaction rolled back because it has been marked as rollback-only

方法加上@Transactional 注解,手动数据回滚

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

 

遇到的两个问题:

1.  org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope

 

2.  org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

 

 

我的最终代码如下,解决了以上的两个问题:

    @RequestMapping(value="/insert",produces = "application/json;charset=utf-8", method = RequestMethod.POST)
    @Transactional(propagation = Propagation.NESTED)
    public String insert(@RequestBody SysUser user, HttpServletRequest request, HttpServletResponse response){

        //获取当前登录系统的用户信息
        SysUser currentUser = getUser();
        user.setCreateTime(new Date()); //设置注册时间
        user.setPassword(MD5Tools.generate(user.getPassword()));// 密码MD5转码
        ReturnData returnData = sysUserService.addUser(currentUser, user);

        return returnData.toString();
    }

 

   @Override
    @Transactional(propagation = Propagation.NESTED)
    public ReturnData addUser(SysUser currentUser, SysUser user) {
/*
         * 根据用户名和站点id查询用户是否已经存在
         * */
//        SysUser u = sysUserMapper.selectByLoginNameAndSiteId(user.getLoginName(),user.getSiteId());
        SysUser u = sysUserMapper.selectByLoginNameAndSiteId(user.getLoginName(), null);
        if (u != null)
            return ReturnData.FAIL("用户名已存在");

        //1.添加用户
        int res1 = sysUserMapper.insertSelective(user);
        if (res1 == 0)
            return ReturnData.FAIL("添加失败");

        //2.分配用户角色
        int res2 = userRoleService.insertByUidAndRoleIdList(user.getId(), user.getRoleIds());
        if (res2 == 0) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ReturnData.FAIL("用户角色分配失败,数据回滚");
        }

        //3.分配用户可管理的站点
        int res3 = sysUserSiteService.insertByUidAndSiteIdList(user.getId(), user.getSiteIds());

        //4.设置用户的默认登录站点
        int res4 = sysUserSiteService.setUserDefaultLoginSite(user.getId(), user.getDefaultSiteId());
        if (res3 == 0 | res4 == 0) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ReturnData.FAIL("用户管理站点分配失败,数据回滚");
        }

        return ReturnData.SUCCESS("添加成功");
    }

 

问题分析及解决方法:

出现以上问题一:是因为我在方法 addUser() 上加了注解@Transactional,而方法insert()上没有使用注解@Transactional导致。两个方法都加上注解即可解决

问题一解决后,当在addUser()执行数据回滚操作时,即人为数据回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 时,问题二

出现了。网上搜了好多都说加上try catch 捕获异常,然而任我在哪加都不行,因为问题二的异常是在insert()方法执行结果后才抛出的一个异常,try catch没办法

捕获。解决方法是改变两个方法的事务传播机制,即注解改为 @Transactional(propagation = Propagation.NESTED)。

出现问题二是因为我之前两个方法都使用注解 @Transactional,默认的事务传播机制为 Propagation.REQUIRED。

Spring事务传播机制汇总如下:

Propagation.REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中。默认策略
Propagation.SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
Propagation.MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
Propagation.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与Propagation.REQUIRED类似的操作。

 

可参考:https://blog.csdn.net/qq_30336433/article/details/83111675

 

posted @ 2020-03-26 11:29  L12345  阅读(5393)  评论(1编辑  收藏  举报