专栏首页大数据-数据人生Spring MVC Controller层事物注解不生效

Spring MVC Controller层事物注解不生效

最近在写一个管理台页面,是从页面提交多个form到controller层的,这些form要么都能提交成功,要么都失败。controller层需要进行事物处理,于是简单的加了@Transactional注解,测试的时候,我故意把最后一个表单的某个字段长度设置超长,后台肯定会报data too long exception。代码主体简要如下:

@RestController
@RequestMapping("/chart")
@Transactional
public class ChartController {

    @RequestMapping(value = "/addPie", method = RequestMethod.POST)
    public ResponseEntity addPie(@RequestBody ReqPieDto pieDto) {
         try {
              weChatService.insertCharData(wxChart);
              wxPieService.insertWxPie(pieData);
              wxConditionService.insertWxCondition(conditions);
         } catch (Exception e) {
            rsp=new ResponseEntity("fail", HttpStatus.GONE);
            logger.error("pie chart config fail:",e);
         }
         return rsp;
    }
}

    这个代码存在很明显的问题,首先对Spring的事物机制没有理解。默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚,spring aop异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过配置来捕获特定的异常并回滚。换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚。

  解决方案: 

  方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理

  方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常。

  那就修改代码,Controller层修改后代码如下:

@RestController
@RequestMapping("/chart")
@Transactional
public class ChartController {

    @RequestMapping(value = "/addPie", method = RequestMethod.POST)
    public ResponseEntity addPie(@RequestBody ReqPieDto pieDto) {
         try {
              weChatService.insertCharData(wxChart);
              wxPieService.insertWxPie(pieData);
              wxConditionService.insertWxCondition(conditions);
         } catch (Exception e) {
              rsp=new ResponseEntity("fail", HttpStatus.GONE);
              logger.error("pie chart config fail:",e);
              throw new SystemException("添加饼图配置失败");
         }
         return rsp;
    }
}

    Service层代码也要抛出异常:

    public void insertWxCondition(WxConditions conditions){
        try {
            mapper.insertSelective(conditions);
        } catch (Exception e) {
            logger.error("insert into report config conditions data fail");
            throw new SystemException("insert into report config conditions data fail", e);
        }
    }

    这时候,事物是回滚了,但是页面显示的返回结果却是这样的:



    到这里,事物问题虽然解决了,但是页面的返回信息太不友好了。这是因为Controller方法抛出异常后,程序就中断了,中断后,直接把异常抛给前台页面了。如此看来,在Contrller层进行这种事物处理的时候,既要保证事物的执行,又不要抛出异常、返回自定义消息给前台页面,这二者不可兼得。那就只有一个办法了,把3个service封装到另外一个service层进行事物控制,然后抛出异常,代码如下:

public void insertPieCharData(ReqPieDto reqPieDto) {
        try {
            this.insertCharData(wxChart);
            wxPieService.insertWxPie(pieData);
            wxConditionService.insertWxCondition(conditions);
            }
            
        } catch (Exception e) {
            
            logger.error("pie chart config fail:",e);
            throw new SystemException("添加饼图配置失败");
        }
        
    }

     然后Controller层去掉trasaction注解,否则异常信息还是会被抛到前台页面,在catch exception中处理异常,代码如下:

    @RequestMapping(value = "/addPie", method = RequestMethod.POST)
    public ResponseEntity addPie(@RequestBody ReqPieDto reqPieDto) {
        
        logger.info("receive request pie config dto:{}",JsonUtil.toFullJson(reqPieDto));
        ResponseEntity rsp=new ResponseEntity("SUCCESS", HttpStatus.OK);
        
        try {
            wxChartService.insertPieCharData(reqPieDto);
        } catch (Exception e) {
            rsp=new ResponseEntity("系统异常", HttpStatus.BAD_REQUEST);
        }
       
        logger.info("返回消息:{}",JsonUtil.toFullJson(rsp));
        return rsp;
    }

     问题搞定。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SVN的使用(一)---删除SVN项目

    在使用SVN前,如果本机上面已经存在SVN版本,就必须先把原来的.svn删除。在使用SVN后,我们也常由于要部署生产环境、项目过大等原因(svn版本控制文件估计...

    幽鸿
  • Linux环境搭建svn服务器

    官网下载:http://subversion.apache.org/packages.html

    幽鸿
  • 在Linux下如何使用shell操作数据库

       我们一般在Windows下采用客户端连接数据库,也有直接在Linux下连接数据库的。但是,当我们想对数据库进行自动化管理的时候,比如:想通过shell脚本...

    幽鸿
  • 从0到1搭建视频通话系统,我1天就搞定了

    最近被老大分配了一个任务,他打开微信视频聊天,发起多人视频,指着功能界面说,“你看我们的产品也是有多人会议的场景,我们也加一个这样的功能,也不用很复杂,就仿照微...

    腾讯云视频
  • 动态 | 微软亚洲研究院资深研究员梅涛:原来视频可以这么玩了! | CCF-GAIR 2017

    7月9日,由CCF主办,雷锋网与香港中文大学(深圳)承办的CCF-GAIR 2017全球人工智能与机器人峰会进入了第三天。在CV+专场首场,微软亚洲研究院资深研...

    AI科技评论
  • zookeeper应用

    通过上一篇的学习,对zookeeper大致有了一些了解,但是想在实际开发与合适的业务场景中使用,还是需要依赖更多深入的学习,同时在项目中不断的实实践,发现问题并...

    sucl
  • Mac中使用Mitmproxy/Charles拦截移动设备网络请求

    拦截http proxy的软件很多,如 Fiddler,Charles等,能够实现对http通信的拦截,可以查验Request和Response参数,特别是移动...

    剑行者
  • java初级笔记----final、static、匿名对象、内部类

    一、final 1、final可以用来修饰类,方法,成员变量, 2、final修饰类不可以被继承,但是可以继承其他类。 3、final修饰的方法不可...

    曼路
  • Flux 是什么?

    Flux 作为一种全新的方式,用于支持建立复杂的可扩展用户界面。当你在网上搜寻Flux的相关资料时,能了解到的大概也就是类似以上这些内容了。但我们该如何定义这样...

    博文视点Broadview
  • 国际顶刊《PNAS》:爱发朋友圈的人,更容易长寿

    在这个朋友圈里,有人十分活跃,而也有些人是“国家级潜水运动员”,那么,在朋友圈的活跃与否对我们有什么影响呢?

    生信宝典

扫码关注云+社区

领取腾讯云代金券