Java在触发事务回滚之后为什么会再一次回到Servlet开始的地方重新走一次流程?

发布于 2022-09-06 04:10:42 字数 3039 浏览 21 评论 0

代码流程

  1. 前台点击"提交订单"进入BaseServlet.class

  2. BaseServlet.class分发至子类OrderServlet.classsubmitOrder()方法

  3. submitOrder()调用Service层的submitOrder()方法.

  4. 关键是Service层submitOrder()中使用了事务回滚. 这里调用了Dao层两个方法: fun01()fun02(), 其中fun01执行成功, fun02()执行时抛出异常.

  5. catch到异常后, 执行回滚. 然后关闭连接.

然后, 异常诡异的是, 程序并没有在回滚、关闭连接后结束,而是再一次进入BaseServlet
再一次执行一次上述流程,而这一次,由于第一次已经将线程绑定的连接关闭了。所以自然出现异常:不能操作已经关闭的连接。
我的疑惑是:为什么它走了两次这个流程?是因为我调用了个dao层的插入数据的方法吗?
还是或事物回滚就是从头在执行要一遍流程呢?

这个异常, 导致回滚技术无法实现呀.

代码片段(图片)

clipboard.png

代码片段源码

Servlet层

public String submitOrder(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ...

        Debug.log("进入方法:submitOrder...");       // 打印信息
        
        boolean flag = false;
        // 调用service层方法 
        flag = orderService.submitOrder( pids, checkeds, quantitys, user );
        // 提交成功 --> order_info.jsp页面  失败 --> info.jsp
        if( flag ) {
            return goOrderInfoUI(req, resp);
        }else {
            req.setAttribute("error", "提交订单失败!");
            return "/info.jsp";
        }
        
    }

service层

...
// 获得*线程绑定的连接*
        Connection conn = null;
        try {
            conn = C3P0Util.getConnection();
            Debug.log("连接=="+conn);
            // 开启事务
                // 由于插入要么都成功, 要么都失败, 所以需要用事务操作
            Debug.log("进入try");
            conn.setAutoCommit(false);
            Debug.log("开启事务");
            // 调用dao插入数据库
            // 插入订单
            orderDao.insertOrder(order);
            Debug.log("order插入走完");
            // 插入订单项
            orderDao.insertOrderItmes( orderItems );
            
            // 提交事务
            conn.commit();
            
            // 方法返回值为true
            Debug.log("事务已提交");
            flag = true;
        }catch(Exception e) {
            Debug.log("进入外层catch");
            // 回滚事务
            try {
                conn.rollback();
                Debug.log("事务已回滚");
            } catch (SQLException e1) {
                // TODO Auto-generated catch block
                Debug.log("进入内存catch");
                e1.printStackTrace();
            }
        }finally {
            // 关闭连接
            try {
                Debug.log("关闭连接");
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        Debug.log("service走完");
        return flag;
...

注:Debug.log()是自定义方法用来打印信息.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

回忆躺在深渊里 2022-09-13 04:10:42

楼主说已经解决,我粗略的看了下发现还是有一个隐患,catch和finally代码块里面的conn.close要加上非空判断。

維他命╮ 2022-09-13 04:10:42

lz今天再次调试的时候, 因为开始出现了一个Servlet没有找到, 就顺手clean了下Tomcat和项目的缓存, 然后再次调试, 居然诡异般的好了...
哎 , 无心插柳柳成荫, 里面的机制太让人费解了.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文