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的编写执行。