SSH中hibernate窍门总结

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
@Repository
public 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
@Transactional
public 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的编写执行。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值