鍍金池/ 問答/Java  數(shù)據(jù)庫  網(wǎng)絡(luò)安全/ Java在觸發(fā)事務(wù)回滾之后為什么會(huì)再一次回到Servlet開始的地方重新走一次流

Java在觸發(fā)事務(wù)回滾之后為什么會(huì)再一次回到Servlet開始的地方重新走一次流程?

代碼流程

  1. 前臺(tái)點(diǎn)擊"提交訂單"進(jìn)入BaseServlet.class

  2. BaseServlet.class分發(fā)至子類OrderServlet.classsubmitOrder()方法

  3. submitOrder()調(diào)用Service層的submitOrder()方法.

  4. 關(guān)鍵是Service層submitOrder()中使用了事務(wù)回滾. 這里調(diào)用了Dao層兩個(gè)方法: fun01()fun02(), 其中fun01執(zhí)行成功, fun02()執(zhí)行時(shí)拋出異常.

  5. catch到異常后, 執(zhí)行回滾. 然后關(guān)閉連接.

然后, 異常詭異的是, 程序并沒有在回滾、關(guān)閉連接后結(jié)束,而是再一次進(jìn)入BaseServlet
再一次執(zhí)行一次上述流程,而這一次,由于第一次已經(jīng)將線程綁定的連接關(guān)閉了。所以自然出現(xiàn)異常:不能操作已經(jīng)關(guān)閉的連接。
我的疑惑是:為什么它走了兩次這個(gè)流程?是因?yàn)槲艺{(diào)用了個(gè)dao層的插入數(shù)據(jù)的方法嗎?
還是或事物回滾就是從頭在執(zhí)行要一遍流程呢?

這個(gè)異常, 導(dǎo)致回滾技術(shù)無法實(shí)現(xiàn)呀.

代碼片段(圖片)

clipboard.png

代碼片段源碼

Servlet層

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

        Debug.log("進(jìn)入方法:submitOrder...");       // 打印信息
        
        boolean flag = false;
        // 調(diào)用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);
            // 開啟事務(wù)
                // 由于插入要么都成功, 要么都失敗, 所以需要用事務(wù)操作
            Debug.log("進(jìn)入try");
            conn.setAutoCommit(false);
            Debug.log("開啟事務(wù)");
            // 調(diào)用dao插入數(shù)據(jù)庫
            // 插入訂單
            orderDao.insertOrder(order);
            Debug.log("order插入走完");
            // 插入訂單項(xiàng)
            orderDao.insertOrderItmes( orderItems );
            
            // 提交事務(wù)
            conn.commit();
            
            // 方法返回值為true
            Debug.log("事務(wù)已提交");
            flag = true;
        }catch(Exception e) {
            Debug.log("進(jìn)入外層catch");
            // 回滾事務(wù)
            try {
                conn.rollback();
                Debug.log("事務(wù)已回滾");
            } catch (SQLException e1) {
                // TODO Auto-generated catch block
                Debug.log("進(jìn)入內(nèi)存catch");
                e1.printStackTrace();
            }
        }finally {
            // 關(guān)閉連接
            try {
                Debug.log("關(guān)閉連接");
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        Debug.log("service走完");
        return flag;
...

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

回答
編輯回答
帥到炸

lz今天再次調(diào)試的時(shí)候, 因?yàn)殚_始出現(xiàn)了一個(gè)Servlet沒有找到, 就順手clean了下Tomcat和項(xiàng)目的緩存, 然后再次調(diào)試, 居然詭異般的好了...
哎 , 無心插柳柳成蔭, 里面的機(jī)制太讓人費(fèi)解了.

2018年8月18日 19:36
編輯回答
骨殘心

樓主說已經(jīng)解決,我粗略的看了下發(fā)現(xiàn)還是有一個(gè)隱患,catch和finally代碼塊里面的conn.close要加上非空判斷。

2017年9月14日 13:28