標籤:分享 理解 興趣 cat window config 標籤 ber 開啟
1.問題
這兩天弄一個項目,串連了mysql。第一天訪問資料庫沒問題,第二天就報錯,異常如下:
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
這裡只摘取一段,很是頭疼。去網上查,大多是說mysql的wait_timeout預設為8小時,mysql資料庫中是28800s。如果在wait_timeout秒期間內,資料庫連接一直處於等待狀態,那麼mysql就將該串連關閉,這時你的java應用的串連池仍然合法的持有該串連的引用。所以你第二天操作資料時,會報錯。
2.解決
一開始按照網上的思路是更改mysql資料庫的wait_timeout欄位,最大值是24天/365天(windows/linux)。或者改mysql的設定檔——my.ini/my.cnf(windows/linux)。可是後來想了想,這樣過一段時間又會報錯,該怎麼解決呢。於是後決定試試看hibernate,看看通過這個架構還會導致問題出現嗎
3.Hibernate配置
首先引入jar:
少一個基本會出現各種各樣的問題,mysql-connector千萬記得。
接著在src目錄下寫設定檔:hibernate.cfg.xml
這裡要注意url裡面的值,useUnicode=true&
它與jdbc的寫法不同,他需要用& 代替; 不然會報錯。
接著我們建個包,在這個包裡面寫個pojo對應資料庫欄位。同時還要寫個對應pojo的映射xml:
user類沒什麼好說的,跟自己資料庫欄位對應即可
這個xml具體配置如下:
class標籤下面name對應的是pojo,table是表名。
id是映射的唯一標識,也就是表中的主鍵。要注意的是<generator>標籤裡的class屬性。我這裡寫的assigned,意思是使用者自訂id,即給定一個id
還有其他6個屬性,感興趣的可以百度,這裡就不做介紹了。
4.寫一個Util類擷取Session
package com.hibernate.DBUtil;import org.hibernate.HibernateException;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class HibernateUtil { private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); private static SessionFactory sessionFactory = null; // SessionFactory對象 static { try { Configuration cfg = new Configuration().configure(); // 載入Hibernate設定檔 sessionFactory = cfg.buildSessionFactory(); } catch (Exception e) { System.err.println("建立會話工廠失敗"); e.printStackTrace(); } } // 擷取Session public static Session getSession() throws HibernateException { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } /** * 重建會話工廠 */ public static void rebuildSessionFactory() { try { Configuration cfg = new Configuration().configure(); // 載入Hibernate設定檔 sessionFactory = cfg.buildSessionFactory(); } catch (Exception e) { System.err.println("建立會話工廠失敗"); e.printStackTrace(); } } // 擷取SessionFactory對象 public static SessionFactory getSessionFactory() { return sessionFactory; } // 關閉Session public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); // 關閉Session } }}
這裡有必要說一下ThreadLocal。因為session是線程不安全的,為瞭解決並發的問題,防止資料汙染,我們在建立session時把她放進ThreadLocal裡,這是一個新思路。並不像之前的加synchronized,要程式員自己在各個不同的地方加,這樣會顯的很煩亂。具體ThreadLocal介紹這裡貼一個部落格,個人覺得理解的很到位:http://blog.csdn.net/lufeng20/article/details/24314381 ThreadLocal源碼內的情況也確實如他所說。
5.CRUD
上面配置好了hibernate,下面來寫一些方法來操作資料庫
具體方法如下:
package com.hibernate.DBUtil;import org.hibernate.Session;import com.hibernate.Entity.User;public class HibernateORM { private HibernateUtil hibernateinit = null; private Session session = null; public void insert(Object obj) { // Hibernate的持久化操作 try { session = hibernateinit.getSession(); // 擷取session session.beginTransaction(); // 開啟事務 session.save(obj); // 執行資料庫添加操作 session.getTransaction().commit();// 事務提交 System.out.println("資料添加成功"); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("資料添加失敗"); e.printStackTrace(); } finally { hibernateinit.closeSession(); } } //get方法是在不確定資料庫是否存在該資訊的情況下擷取detail public void getDetail() { try { session = hibernateinit.getSession(); User user = (User) session.get(User.class, new Integer("4")); System.out.println("使用者ID:" + user.getId() + ",使用者姓名:" + user.getName()); System.out.println("第一次裝載對象"); User user2 = (User) session.get(User.class, new Integer("4")); System.out.println("第二次裝載對象"); } catch (Exception e) { System.out.println("get()方法對象裝載失敗!"); e.printStackTrace(); } finally { hibernateinit.closeSession(); } } //load方法是在給定ID的情況下擷取detail public void loadDetail(){ try { session = hibernateinit.getSession(); User user = new User(); session.load(user, new Integer("1")); //裝載對象 System.out.println("使用者ID:" + user.getId() + ",使用者姓名:" + user.getName()); } catch (Exception e) { System.out.println("load()方法對象裝載失敗!"); e.printStackTrace(); }finally { hibernateinit.closeSession(); } } public void delete(){ try { session = hibernateinit.getSession(); session.beginTransaction(); User user = (User)session.get(User.class, new Integer("3")); session.delete(user); session.flush(); session.getTransaction().commit(); System.out.println("對象刪除成功!"); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("對象刪除失敗!"); e.printStackTrace(); }finally { hibernateinit.closeSession(); } } public void update(){ try { session = hibernateinit.getSession(); session.beginTransaction(); User user = (User) session.get(User.class, new Integer("4")); user.setName("233"); session.flush(); session.getTransaction().commit(); System.out.println("對象修改成功"); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("對象修改失敗"); e.printStackTrace(); }finally { hibernateinit.closeSession(); } } }
簡單的寫了一下,這裡要注意,在增刪改這些操作上,要加事務,不然會報一個Transaction的錯誤。
最後寫一個test測試一下:
自己試了裡面一些方法,發現控制台輸出了SQL語句和執行結果:
確實和資料庫能對應起來,CRUD操作也都沒有問題。
6.昨天寫好這些東西後,對資料庫操作了一番發現沒有問題,今天看看會不會出現通過JDBC操作mysql的wait_timeout問題。結果沒有出現,這個方法應該可以不通過修改mysql資料庫從而解決。下面還要進行長時間觀察,看看有沒有這個問題,這裡先做一個記錄。
初識Hibernate