最近在做一個項目,用的是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