花了一下午重构了下数据库交互层的代码,减少了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() { @Override public Object doSomething(Session session) { session.save(obj); return null; } }); } public static void deleteById(final Class c, final long id) { templatedExec(new ActionInSession() { @Override public 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() { @Override public Object doSomething(Session session) { session.delete(obj); return null; } }); } public static Object findById(final Class c, final long id) { return templatedExec(new ActionInSession(){ @Override public 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() { @Override public 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() { @Override public Object doSomething(Session session) { return session.createQuery(hql).list(); } }) ; } }
在《代码整洁之道》中谈到, 当引入第三方框架或代码时,要谨慎地控制其作用的范围及影响,而不是简单地无所顾忌地使用其带来的便利。换句话说,要将第三方代码局限在一个范围内,当需要换用框架时,不至于影响系统整体,这就是所谓的第三方边界。HibernateUtils 就是这样一个第三方边界, 将 Hibernate 框架的影响范围限制在一个类中, 需要改动的时候,只需要改动少量的地方即可。当然,这里主要起演示性的作用,在大型项目中,可能需要采用更精细的手段来实现真正稳固可靠的第三方边界。
后记: 实际上, Spring HibernateTemplate 已经做了此工作,而且比本文做的更可靠, 多了解一些开源组件、库, 对于避免做重复工作是非常有益的。 当然, 使用自己编写的组件最大的优势是简单,灵活, 不必为了一个轮胎去借一辆汽车。