SSH中hibernate窍门总结

来源:互联网 发布:淘宝750海报 编辑:程序博客网 时间:2024/05/19 23:17

hibernate 就是ORM框架,就是要配置关系外键。
你不配置你用他干啥,换mybatis得了。
小系统或大项目中数据量不大的子系统能使用hibernate就用hibernate,方便简单。
这里我个人有摸索出的窍门,大家可以参考一下。

首先,逆向生成hibernate对象配置,保留多对一关系,与之对应的一对多掉,按需配置抓取方式,按需配置懒加载。
然后DAO可以使用DAO的模板类,贴出我丰富过的模版类。(使用了spring的事务管理),具体业务接口继承这个模版DAO接口,然后可以自定义一些特定的方法,然后具体业务接口的实现类继承模版DAO的实现即可。

模版接口类GenericDaoI:

package cn.zzy.tm.dao;import java.io.Serializable;import java.util.List;import org.hibernate.criterion.Criterion;import cn.zzy.tm.model.db.PageBean;/** * 增删改查通用接口 Dao层的接口可以继承本基本接口进行扩展 *  * Hibernate使用小记 根据业务,常用的字段需要join的就fetch=join,不需要的就开lazy,fetch=select *  * DAO泛型模板类, 提供各类基础的查询模版方法,也提供懒加载的回调接口,方便初始化懒加载的数据 *  * ,(解决代码分层session关闭后懒加载失效的问题)这个偶尔使用,一般很少使用这些回调的接口, *  * 因为特殊的查询全用HQL了,而HQL是可以指定特殊字段的抓取方式的。 *  *  * 如果某个实体内的一些字段内,只有某些少数业务查询需要fetch=join,其他大部分都不需要这部分数 *  * 据的时候,建议配置文件开lazy,fetch=select 查询全用HQL指定left join fetch来抓取指定字段 *  * 因为HQL查询里配置的抓取方式全无效,默认全是lazy+select,需要在代码里指定 比方说 from Teacher as t left join * fetch t.teacherAcademicTitle *  *  *  * @author 赵泽洋 *  * @param <T> *            要实现基本操作的bean的类 */public interface GenericDaoI<T extends Serializable> {    /**     * 回调接口,初始化代理对象用     *      * @author zhaozeyang     *      */    public interface InitializeObjCallBack<T> {        public void initializeObj(final T obj);    }    /**     * 回调接口,初始化代理对象LIST用     *      * @author zhaozeyang     *      */    public interface InitializeListCallBack<T> {        public void initializeList(final List<T> ls);    }    /**     * 新增一条数据     *      * @param entity     *            实体     */    public abstract void create(final T entity);    /**     * 新增一条数据 若存在则更新     *      * @param entity     */    public abstract void createOrUpdate(final T entity);    /**     * 根据主键查实体     *      * @param id     *            主键     * @return 查询结果     */    public abstract T findById(final Serializable id);    /**     * 根据主键查实体     *      * @param id     * @param callback     *            回调接口     * @return     */    public abstract T findById(final Serializable id,            InitializeObjCallBack<T> callback);    /**     * 根据id删数据,可传多个id     *      * @param entityids     *            id序列     */    public abstract void deleteById(Serializable... entityids);    /**     * 更新实体类到数据库     *      * @param entity     *            要更新的实体类     */    public abstract void update(final T entity);    /**     * 查所有记录     *      * @return 查询结果     */    public abstract List<T> findAll();    /**     * 查所有记录     *      * @param callBack     *            回调接口     * @return     */    public abstract List<T> findAll(InitializeListCallBack<T> callBack);    /**     * HQL查记录     *      * @param strHQL     *            HQL语句     * @param params     *            参数     * @return 查询结果     */    public abstract List<T> findByHQL(final String strHQL,            final Object... params);    /**     * HQL查记录     *      * @param callBack     *            回调接口     * @param strHQL     *            HQL语句     * @param params     *            参数     * @return 查询结果     */    public abstract List<T> findByHQL(InitializeListCallBack<T> callBack,            final String strHQL, final Object... params);    /**     * HQL分页查找     *      * @param strHQL     *            HQL语句     * @param currentPage     *            查第几页     * @param pageSize     *            一个页面数据的条数     * @param params     *            查询结果     * @return     */    public abstract PageBean<T> findByPage(final String strHQL,            final int currentPage, final int pageSize, final Object... params);    /**     * HQL分页查找     *      * @param callBack     *            回调接口     * @param strHQL     * @param currentPage     * @param pageSize     * @param params     * @return     */    public abstract PageBean<T> findByPage(InitializeListCallBack<T> callBack,            final String strHQL, final int currentPage, final int pageSize,            final Object... params);    /**     * 用Criteria方式查找数据     *      * @param prams     * @return     */    public List<T> findByCriteria(Criterion... prams);    /**     * 用Criteria方式查找数据     *      * @param callBack     *            回调接口     * @param prams     * @return     */    public List<T> findByCriteria(InitializeListCallBack<T> callBack,            Criterion... prams);    public Integer getCount();    /**     * 执行HQL delete update操作     */    public int executeHQL(final String strHQL, final Object... params);    /**     * 当返回只有一个实例的时候使用     *      * @param strHQL     * @param params     * @return     */    public Object ExecuteScalarByHql(final String strHQL,            final Object... params);}

实现类GenericDaoImpl:

package cn.zzy.tm.dao.impl;import java.io.Serializable;import java.util.List;import javax.annotation.Resource;import org.hibernate.Criteria;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.criterion.Criterion;import org.hibernate.criterion.Projections;import cn.zzy.tm.dao.GenericDaoI;import cn.zzy.tm.model.db.PageBean;import cn.zzy.tm.utils.GenericsUtils;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;/** * Dao层模版类 *  * @author 赵泽洋 *  * @param <T> *            要实现基本操作的bean的类 *  */@Transactional@Repositorypublic class GenericDaoImpl<T extends Serializable> implements GenericDaoI<T> {    /**     * 获取实体类类型     */    @SuppressWarnings("unchecked")    protected Class<T> persistentClass = GenericsUtils            .getSuperClassGenricType(this.getClass());    /**     * 若反射获得泛型类类型失效,则由此方法手动设置     *      * @param entityClass     *            实体类类型     */    public void setEntityClass(Class<T> entityClass) {        this.persistentClass = entityClass;    }    /**     * 由spring管理的SessionFactory,注解获取     */    @Resource    protected SessionFactory sessionFactory;    public void create(T entity) {        sessionFactory.getCurrentSession().persist(entity);    }    public void createOrUpdate(T entity) {        sessionFactory.getCurrentSession().saveOrUpdate(entity);    }    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public T findById(Serializable id) {        return this.findById(id, null);    }    @SuppressWarnings("unchecked")    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public T findById(Serializable id, InitializeObjCallBack<T> callback) {        if (id == null)            throw new RuntimeException(this.persistentClass.getName()                    + ":传入的实体id不能为空");        Object object = sessionFactory.getCurrentSession().get(                this.persistentClass, id);        if (callback != null)            callback.initializeObj((T) object);        return (T) object;    }    public void deleteById(Serializable... entityids) {        Session session = sessionFactory.getCurrentSession();        for (Serializable id : entityids) {            session.delete(session.get(this.persistentClass, id));        }    }    public void update(T entity) {        sessionFactory.getCurrentSession().merge(entity);    }    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public List<T> findAll() {        return this.findByCriteria();    }    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public List<T> findAll(InitializeListCallBack<T> callBack) {        return this.findByCriteria(callBack);    }    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public List<T> findByHQL(String strHQL, Object... params) {        return this.findByHQL(null, strHQL, params);    }    @SuppressWarnings("unchecked")    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public List<T> findByHQL(InitializeListCallBack<T> callBack, String strHQL,            Object... params) {        Session session = sessionFactory.getCurrentSession();        Query query = session.createQuery(strHQL);        for (int i = 0; i < params.length; i++) {            query.setParameter(i, params[i]);        }        List<T> ls = query.list();        if (callBack != null)            callBack.initializeList(ls);        return ls;    }    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public PageBean<T> findByPage(String strHQL, int currentPage, int pageSize,            Object... params) {        return this.findByPage(null, strHQL, currentPage, pageSize, params);    }    @SuppressWarnings("unchecked")    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public PageBean<T> findByPage(InitializeListCallBack<T> callBack,            String strHQL, int currentPage, int pageSize, Object... params) {        // 步骤1:创建一个PageBean对象        PageBean<T> pageBean = new PageBean<T>();        // 步骤2:获取一个数据库链接session        Session session = sessionFactory.getCurrentSession();        // 步骤3:执行HQL语句完成查询动获取本页内的固定条数的数据        Query query = session.createQuery(strHQL);        // 步骤4:设置查询条件-参数条件        for (int i = 0; i < params.length; i++) {            query.setParameter(i, params[i]);        }        // 步骤5:设置查询条件-每页的启始记录下标 (当前也是-1)*每页个数        query.setFirstResult((currentPage - 1) * pageSize);        // 步骤6:设置查询条件-控制查询记录的个数        query.setMaxResults(pageSize);        // 步骤7:获取数据集合并且赋值给pageBean对象的data属性        pageBean.setData(query.list());        // 步骤8:将输入的HQL语句动态查分成符合返回记录个数的HQL语句        strHQL = "select count(*) "                + strHQL.substring(strHQL.toLowerCase().indexOf("from"));        //如果自定义了fetch,必须去掉fetch才能查出count(*)        strHQL = strHQL.replace("fetch", "");        // 步骤9:执行HQL语句完成查询动获取本页内的固定条数的数据        query = session.createQuery(strHQL);        // 步骤10:设置查询条件-参数条件        for (int i = 0; i < params.length; i++) {            query.setParameter(i, params[i]);        }        // 步骤11:获取查询结果并且赋值给pageBean对象的totalRows        pageBean.setTotalRows(Integer.parseInt(query.uniqueResult().toString()));        // 步骤12:为剩余的pageBean属性赋值        pageBean.setCurrentPage(currentPage);        pageBean.setPageSize(pageSize);        if (callBack != null)            callBack.initializeList(pageBean.getData());        return pageBean;    }    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public List<T> findByCriteria(Criterion... prams) {        return this.findByCriteria(null, prams);    }    @SuppressWarnings("unchecked")    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)    public List<T> findByCriteria(InitializeListCallBack<T> callBack,            Criterion... prams) {        Session session = sessionFactory.getCurrentSession();        Criteria criteria = session.createCriteria(this.persistentClass);        for (Criterion criterion : prams) {            criteria.add(criterion);        }        List<T> ls = criteria.list();        if (callBack != null)            callBack.initializeList(ls);        return ls;    }    public Integer getCount() {        Session session = sessionFactory.getCurrentSession();        Criteria c = session.createCriteria(this.persistentClass);        c.setProjection(Projections.rowCount());        return  (Integer) c.uniqueResult();    }    public int executeHQL(String strHQL, Object... params) {        Session session = sessionFactory.getCurrentSession();        Query query = session.createQuery(strHQL);        for (int i = 0; i < params.length; i++) {            query.setParameter(i, params[i]);        }        return query.executeUpdate();     }    public Object ExecuteScalarByHql(String strHQL, Object... params) {        Session session = sessionFactory.getCurrentSession();        Query query = session.createQuery(strHQL);        for (int i = 0; i < params.length; i++) {            query.setParameter(i, params[i]);        }        return query.uniqueResult();    }}

具体实现随便举个例子:
具体业务接口AdminBizI :

package cn.zzy.tm.logic;import cn.zzy.tm.dao.GenericDaoI;import cn.zzy.tm.model.db.Admin;public interface AdminBizI extends GenericDaoI<Admin> {    /**     * 获取能用的管理员数量,没被禁用的     * @return     */    public Long getUseableAdmin();}

具体业务接口的实现类:

package cn.zzy.tm.logic.impl;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import cn.zzy.tm.dao.impl.GenericDaoImpl;import cn.zzy.tm.logic.AdminBizI;import cn.zzy.tm.model.db.Admin;@Service@Transactionalpublic class AdminBizImpl extends GenericDaoImpl<Admin> implements AdminBizI {    public Long getUseableAdmin() {        return (Long) this                .ExecuteScalarByHql("select count(*) from Admin as t where t.adminSuspended=0");    }}

接下来是关于代码分层导致不能取得懒加载配置的数据然后hibernate session关闭的问题,解决方法有很多,但是不推荐使用spring中扩大session生命周期的方法,即OpenSessionInViewFilter,系统的性能会因为用户的网络状况受到影响,当request在生成页面完成后,session才会被释放,所以如果用户的网络状况比较差,或生成整张页面损耗服务器CPU耗时比较长时,那么连接池中的链接会迟迟不被回收,造成内存增加,系统性能受损,并发量大的时候肯定挂了。

我的解决方法就如上模板类的代码所示,回调接口,
在回调接口里把需要的数据load进来就好。
或关联查询的时候用HQL自定义抓取方式,只抓取需要的

回调接口使用举例:

studentTask = studentTaskBizImpl.findById(sessionStu.getStudentId(),                new InitializeObjCallBack<StudentTask>() {                    public void initializeObj(StudentTask obj) {                        if (obj != null) {                            Hibernate.initialize(obj.getTask());                            Hibernate.initialize(obj.getTask().getTeacher());                        }                    }                });

自定义抓取方式举例

pgb = taskBizImpl                        .findByPage(                                "from Task as t "                                        + "left join fetch t.tmtype left join fetch t.dicByTaskWhereToDo left join fetch t.dicByTaskState left join fetch t.dicByTaskType left join fetch t.teacher  "                                        + "where t.dicByTaskState.dicId=?  order by t.tmtype.tmtypeId, t.taskCreateTime ",                                page, rows, "200");

当然更复杂的直接用sql,可以用hibernate里的sql查询方式,自定义结果集的bean,或者spring里的JdbcTemplate。

当然涉及到项目数据量很大,肯定是不使用关系,也就不会使用hibernate,一般都把复杂业务写成存储过程,用mybatis方便sql的编写执行。

0 0
原创粉丝点击