MySQL的存儲引擎造成的事務無法回滾

最近在做一個項目,用的是hibernate框架,數據庫是mysql。我是在javaweb的過濾器上通過session與線程綁定,得到當前線程綁定的session然後開啓事務,然後進行放心,對異常進行捕獲並回滾。這是在沒有使用spring框架的事務處理,而又爲了延長hibernate中session的聲明週期所採用的方法,即OpenSessinInView。在過濾器開啓事務後,放行執行的代碼都會在事務之內,出現異常進行捕獲可以回滾。代碼如下:

public class OpenSessionInView implements Filter {

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		Session session = null;
		Transaction tx = null;
		try {
			session = ClientSessionFactory.getCurrentSession();
			tx = session.beginTransaction();
			//=======業務開始=======
			chain.doFilter(request, response);
			//=======業務結束=======
			
			tx.commit();
		} catch (AjaxException e) {
			response.setCharacterEncoding("utf-8");
			if (tx != null) {
				tx.rollback();
			}
			String error = e.getMessage();
			response.getWriter().print(error);
		} catch (Exception e) {
			if (tx != null) {
				tx.rollback();
			}
			e.printStackTrace();
			request.setAttribute("error", e.getMessage());
			request.getRequestDispatcher("/jsps/error.jsp")
					.forward(request, response);
		} finally{
			ClientSessionFactory.closeCurrentSession();
		}
	}

	public void init(FilterConfig fConfig) throws ServletException {
		
	}

	public void destroy() {
		
	}

}

在實際情況中,我在servlet中執行了一個添加函數,往數據庫中添加一條記錄,然後繼續執行下面的代碼,結果發生了異常。這時發現,數據庫中的數據並沒有回滾。在設置斷點調試後,發現,過濾器中的事務有開啓,異常也有被捕獲,事務回滾的代碼也有被執行,但是數據庫中的數據就是不回滾,造成了垃圾數據的產生。

同時,也發現了數據庫中存在的一個問題,所有建的外鍵,都無效,自動變成了索引,真的是奇怪。

後來在網上找了很久,才發現這不是代碼的問題,而是數據庫的問題。MySQL數據庫的存儲引擎有好幾種,有的不支持事務和外鍵,有的支持。在mysql中輸入sql語句 SHOW ENGINES可以查看當前數據庫支持的引擎:



第二列Support中DEFAULT表示目前數據庫的默認引擎。這個引擎是管理非事務表,不支持事務,不支持外鍵,但是訪問速度快,對事務完整性沒有要求或者以SELECT、INSERT爲主的應用基本都可以使用這個引擎來創建表。這也就解釋了我遇到的數據庫不能回滾,表不能建外鍵的原因。

從圖中可以看到,只有InnoDB這個引擎支持了事務,所以想在程序中使用事務,並在出現異常時回滾,就要使用這個引擎,即修改一下表的引擎即可。

至此之前的問題都解決了。有時候思考一個問題,不能太單方面,從多角度思考或許就能找到問題的根源。

關於MySQL數據庫引擎的介紹,可參考下面一篇博客:

http://www.cnblogs.com/gbyukg/archive/2011/11/09/2242271.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章