花了一下午重構了下資料庫互動層的代碼,減少了piles of code , 稱起來應該有幾克重吧? 還想到了一個模板方法模式,進一步減少了一大堆的getSession 和 closeSession. 感覺還不錯。錯漏或考慮不周之處,還懇請指出。
package com.ccnu.salary.utils;import java.util.ArrayList;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;/** * 提供 資料庫互動的可複用代碼 * */public class HibernateUtils {private static SessionFactory factory; private HibernateUtils() {}static {Configuration cfg = new Configuration().configure();factory = cfg.buildSessionFactory();}public static SessionFactory getSessionFactory() {return factory;}public static Session getSession() {return factory.openSession();}public static void closeSession(Session session) {if (session != null) {if (session.isOpen()) {session.close();}}}public interface ActionInSession {Object doSomething(Session session);}public static Object templatedExec(ActionInSession ais){Session session = null;try{session = getSession();session.beginTransaction();Object obj = ais.doSomething(session);session.getTransaction().commit();return obj;} catch (Exception e) {e.printStackTrace();session.getTransaction().rollback();} finally {HibernateUtils.closeSession(session);}return null;}public static void save(final Object obj){templatedExec(new ActionInSession() {@Overridepublic Object doSomething(Session session) {session.save(obj);return null;}});}public static void deleteById(final Class c, final long id){templatedExec(new ActionInSession() {@Overridepublic Object doSomething(Session session) {Object obj = session.load(c, id);session.delete(obj);return null;}});}public static void delete(final Object obj){templatedExec(new ActionInSession() {@Overridepublic Object doSomething(Session session) {session.delete(obj);return null;}});}public static Object findById(final Class c, final long id){return templatedExec(new ActionInSession(){@Overridepublic Object doSomething(Session session) {return session.get(c, id);}});}public static Object findByCondition(final String hql, final String param1, final String param2){return templatedExec(new ActionInSession() {@Overridepublic Object doSomething(Session session) {return session.createQuery(hql).setParameter(0, param1).setParameter(1, param2).uniqueResult();}}) ;}public static List findAll(final String hql){return (List) templatedExec(new ActionInSession() {@Overridepublic Object doSomething(Session session) {return session.createQuery(hql).list();}}) ;}}
在《代碼整潔之道》中談到, 當引入第三方架構或代碼時,要謹慎地控制其作用的範圍及影響,而不是簡單地無所顧忌地使用其帶來的便利。換句話說,要將第三方代碼局限在一個範圍內,當需要換用架構時,不至於影響系統整體,這就是所謂的第三方邊界。HibernateUtils 就是這樣一個第三方邊界, 將 Hibernate 架構的影響範圍限制在一個類中, 需要改動的時候,只需要改動少量的地方即可。當然,這裡主要起示範性的作用,在大型項目中,可能需要採用更精細的手段來實現真正穩固可靠的第三方邊界。
後記: 實際上, Spring HibernateTemplate 已經做了此工作,而且比本文做的更可靠, 多瞭解一些開源組件、庫, 對於避免做重複工作是非常有益的。 當然, 使用自己編寫的組件最大的優勢是簡單,靈活, 不必為了一個輪胎去借一輛汽車。