前言
Hibernate的目标是让开发者不用写sql就能实现对象到数据表的映射操作。当然,理想很美好,现实很骨感,在使用Hibernate时会遇到很多问题,如重复的增删改查、批量对象操作、分页等等,所以如果能抽象出这些通用方法,除了提高代码的整洁性,还能提高开发效率。
实现
1、通用接口定义:HibernateBaseDao
import java.util.Collection;
import java.util.List;
/**
* 数据库操作接口:Hibernate BaseDao
* <pre>
* 使用jpa规范,该接口定义了操作数据库的常用api(增、删、改、查)
* jpa操作的是对象,所以接口的参数都是对对象的操作
* spring boot 对jpa的自动配置,放在org.springframework.boot.autoconfigure.com.jpa下面,
* 包含hibernate的自动配置,说明spring默认jpa的实现者是hibernate。
* </pre>
*
*/
public interface HibernateBaseDao<T> {
/**
* 保存实体
* @param t 泛型 保存到数据库的对象
* @return 空
*/
public void save(T t);
/**
* 批量保存实体
* @param objs 泛型数组 保存到数据库的对象
* @return 空
*/
public void save(T[] objs);
/**
* 批量保存实体
* @param objs 泛型集合 保存到数据库的对象
* @return 空
*/
public void save(Collection<T> objs);
/**
* 更新实体
* @param t 泛型 更新到数据库的对象
* @return 空
*/
public void update(T t);
/**
* 批量更新实体
* @param objs 泛型数组 更新到数据库的对象
* @return 空
*/
public void update(T[] objs);
/**
* 批量更新实体
* @param objs 泛型集合 更新到数据库的对象
* @return 空
*/
public void update(Collection<T> objs);
/**
* 删除实体
* @param t 泛型 从数据库删除指定对象
* @return 空
*/
public void delete(T t);
/**
* 批量删除实体
* @param objs 泛型数组 从数据库批量删除对象
* @return 空
*/
public void delete(T[] objs);
/**
* 批量删除实体
* @param objs 泛型集合 从数据库批量删除对象
* @return 空
*/
public void delete(Collection<T> objs);
/**
* 根据主键查询
* @param id Object 根据id字段查询
* @return T
*/
public T getById(Object id);
/**
* 根据主键数组查询
* @param ids id主键数组
* @return List<T>
*/
public List<T> getByIds(Object[] ids);
/**
* 根据字段name查询,该表要存在字段:name
* @param name Object 根据name字段查询
* @return List<T>
*/
public List<T> getByName(Object name);
/**
*
* 查询最小的name字段
* @param name
* @return
*/
public Long getMinName(String name);
/**
* 查询所有记录
* @return List<T>
*/
public List<T> getAll();
/**
* 根据条件集合查询记录
* @param queryConditions 查询条件集合
* @return List<T>
*/
public List<T> get(List<QueryCondition> queryConditions);
/**
* 根据条件集合查询记录,具有排序功能
* @param queryConditions 查询条件集合
* @param orderBy 排序, 如 order by id desc
* @return List<T>
*/
public List<T> get(List<QueryCondition> queryConditions, String orderBy);
/**
* 根据条件集合查询记录,具有排序和分页功能
* @param queryConditions 查询条件集合
* @param orderBy 排序, 如 order by id desc
* @param currentPage 当前页
* @param pageSize 每页显示记录数
* @return List<T>
*/
public List<T> get(List<QueryCondition> queryConditions, String orderBy,
int currentPage, int pageSize);
/**
* 根据条件集合查询单条记录
* @param queryConditions 查询条件集合
* @return T
*/
public T getSingleResult(List<QueryCondition> queryConditions);
/**
* 根据条件查询记录数量
* @param queryConditions 查询条件集合
* @return
*/
public long getRecordCount(List<QueryCondition> queryConditions);
/**
* 根据jpql查询
* @param jpql jpql主要用于JPA查询数据,和SQL语句的语法大同小异
* @param objects 参数
* @return List<?>
*/
public List<?> getByJpql(String jpql, Object...objects);
/**
* 执行jpql语句
* @param jpql jpql主要用于JPA查询数据,和SQL语句的语法大同小异
* @param objects 参数
* @return
*/
public int executeJpql(String jpql, Object...objects);
/**
* 分页查询
* @param queryConditions 查询条件集合
* @param orderBy 排序字段 如:order by id desc
* @param currentPage 当前页
* @param pageSize 每页显示记录数
* @return Pagination<T>
*/
public Pagination<T> getPagination(List<QueryCondition> queryConditions, String orderBy, int currentPage, int pageSize);
/**
* 查找唯一结果
* @param jpql jpql主要用于JPA查询数据,和SQL语句的语法大同小异
* @param objects 参数
* @return T
*/
public T getUniqueResultByJpql(String jpql, Object...objects);
/**
* 执行原生的sql
* @param sql
* @return
*/
public int executeNativeQuerySql(String sql);
/**
* flush缓存
*/
public void flush();
/**
* clear缓存
*/
public void clear();
/**
* 刷新实体
* @param entity
*/
public void refresh(Object entity);
}
2、通用接口实现类:HibernateBaseDaoImpl
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import org.springframework.transaction.annotation.Transactional;
/**
* BaseDao的实现类:BaseDaoImpl
* <pre>
* 使用jpa规范,实现了操作数据库的常用api(增、删、改、查)
* jpa操作的是对象,所以接口的参数都是对对象的操作
* spring boot 对jpa的自动配置,放在org.springframework.boot.autoconfigure.com.jpa下面,
* 包含hibernate的自动配置,说明spring默认jpa的实现者是hibernate。
* </pre>
*
*/
@Transactional
public class HibernateBaseDaoImpl<T> implements HibernateBaseDao<T> {
@PersistenceContext(type=PersistenceContextType.TRANSACTION)
protected EntityManager em;
protected Class<T> clazz;
/**
* 获取子类的真实类型
*/
@SuppressWarnings("unchecked")
public HibernateBaseDaoImpl() {
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
this.clazz = (Class<T>) pt.getActualTypeArguments()[0];
}
@Override
public void save(T t) {
em.persist(t);
}
@Override
public void save(T[] objs) {
for(T obj : objs) {
em.persist(obj);
}
}
@Override
public void save(Collection<T> objs) {
Iterator<T> itr = objs.iterator();
while(itr.hasNext()) {
em.persist(itr.next());
}
}
@Override
public void update(T t) {
em.merge(t);
}
@Override
public void update(T[] objs) {
for(T obj : objs) {
em.merge(obj);
}
}
@Override
public void update(Collection<T> objs) {
Iterator<T> itr = objs.iterator();
while(itr.hasNext()) {
em.merge(itr.next());
}
}
@Override
public void delete(T t) {
em.remove(em.merge(t));
}
@Override
public void delete(T[] objs) {
for(T obj : objs) {
em.remove(em.merge(obj));
}
}
@Override
public void delete(Collection<T> objs) {
Iterator<T> itr = objs.iterator();
while(itr.hasNext()) {
em.remove(itr.next());
}
}
@Override
public T getById(Object id) {
return em.find(clazz, id);
}
@SuppressWarnings("unchecked")
@Override
public List<T> getByIds(Object[] ids) {
if(ids != null && ids.length > 0) {
//拼接id数组为字符串
StringBuilder idBuilder = new StringBuilder("");
for(Object id : ids) {
idBuilder.append(id).append(",");
}
String idStr = idBuilder.toString();
if(idStr.endsWith(",")) {
idStr = idStr.substring(0, idStr.length() - 1);
}
//jpa查询
String className = clazz.getSimpleName();
StringBuilder jpql = new StringBuilder("select o from ");
jpql.append(className).append(" o where o.id in (").append(idStr).append(")");
return em.createQuery(jpql.toString()).getResultList();
}
return Collections.emptyList();
}
@SuppressWarnings("unchecked")
@Override
public List<T> getByName(Object name) {
String className = clazz.getSimpleName();
StringBuilder jpql = new StringBuilder("select o from ");
jpql.append(className).append(" o where o.name='").append(name).append("'");
return em.createQuery(jpql.toString()).getResultList();
}
@Override
public Long getMinName(String name) {
String className = clazz.getSimpleName();
Query query = em.createQuery("select min("+name+") from " + className);
if( query.getSingleResult()==null){
return 0L;
}
return (Long)query.getSingleResult();
}
@SuppressWarnings("unchecked")
@Override
public List<T> getAll() {
String className = clazz.getSimpleName();
StringBuilder jpql = new StringBuilder("select o from ");
jpql.append(className).append(" o ");
return em.createQuery(jpql.toString()).getResultList();
}
@Override
public List<T> get(List<QueryCondition> queryConditions) {
return get(queryConditions, null, 0, 0);
}
@Override
public List<T> get(List<QueryCondition> queryConditions, String orderBy) {
return get(queryConditions, orderBy, 0, 0);
}
@SuppressWarnings("unchecked")
@Override
public List<T> get(List<QueryCondition> queryConditions, String orderBy,
int currentPage, int pageSize) {
Query query = getQuery(queryConditions, orderBy, false);
if(currentPage == 0 && pageSize == 0) {
return query.getResultList();
}else {
return query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).getResultList();
}
}
@SuppressWarnings("unchecked")
@Override
public T getSingleResult(List<QueryCondition> queryConditions) {
Query query = getQuery(queryConditions, null, false);
return (T)query.getSingleResult();
}
@Override
public long getRecordCount(List<QueryCondition> queryConditions) {
Query query = getQuery(queryConditions, null, true);
Object result = query.getSingleResult();
long recordCount = 0L;
if(result != null) {
recordCount = ((Long)result).longValue();
}
return recordCount;
}
@Override
public List<?> getByJpql(String jpql, Object... objects) {
Query query = em.createQuery(jpql);
if(objects != null) {
if (objects != null) {
for(int i = 0; i < objects.length; i ++){
query.setParameter(i, objects[i]);
}
}
}
return query.getResultList();
}
@Override
public int executeJpql(String jpql, Object... objects) {
Query query = em.createQuery(jpql);
if (objects != null) {
for(int i = 0; i < objects.length; i ++){
query.setParameter(i, objects[i]);
}
}
return query.executeUpdate();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Pagination<T> getPagination(List<QueryCondition> queryConditions,
String orderBy, int currentPage, int pageSize) {
List<T> recordList = get(queryConditions, orderBy, currentPage, pageSize);
long recordCount = getRecordCount(queryConditions);
return new Pagination(currentPage, pageSize, recordCount, recordList);
}
@SuppressWarnings("unchecked")
@Override
public T getUniqueResultByJpql(String jpql, Object... objects) {
Query query = em.createQuery(jpql);
if (objects != null) {
for(int i = 0; i < objects.length; i ++){
query.setParameter(i, objects[i]);
}
}
return (T)query.getSingleResult();
}
/**
* 封装jpql语句,根据查询条件获取Query
* @param queryConditions
* @param orderBy
* @param isQueryTotal 是否查询记录总数, true 则查询记录总数
* @return Query
*/
private Query getQuery(List<QueryCondition> queryConditions, String orderBy, boolean isQueryTotal) {
String className = clazz.getSimpleName();
String preJPQL = isQueryTotal? "select count(*) from " : "select o from ";
StringBuilder jpql = new StringBuilder(preJPQL);
jpql.append(className).append(" o where 1=1 ");
Query query = null;
if(queryConditions != null && queryConditions.size() > 0) {
//构造jpql语句
Iterator<QueryCondition> iterator = queryConditions.iterator();
while(iterator.hasNext()) {
QueryCondition queryCondition = iterator.next();
if(queryCondition!=null) {
if(queryCondition.getOperator().equals(QueryCondition.CUSTOM)) {
jpql.append(" and (").append(queryCondition.getCustomJPQL()).append(")");
}
if(queryCondition.getValue() != null && !"".equals(queryCondition.getValue())) {
//如果占位符名称是*.*格式,则换成*_*格式。且:和名称之间不能有空格
String placeholder = queryCondition.getField().indexOf(".")!=-1 ? queryCondition.getField().replace(".", "_"):queryCondition.getField();
jpql.append(" and o.")
.append(queryCondition.getField().trim())
.append(" ")
.append(queryCondition.getOperator())
.append(":")
.append(placeholder.trim());
}
}
}
}
if(orderBy != null && !"".equals(orderBy)) {
jpql.append(" ").append(orderBy);
}
query = em.createQuery(jpql.toString());
if(queryConditions != null && queryConditions.size() > 0) {
//为参数赋值
Iterator<QueryCondition> iterator2 = queryConditions.iterator();
while(iterator2.hasNext()) {
QueryCondition queryCondition = iterator2.next();
if(queryCondition!=null) {
if(queryCondition.getValue() != null && !"".equals(queryCondition.getValue())) {
//将占位符中的.替换成_
queryCondition.setField(queryCondition.getField().indexOf(".") != -1 ? queryCondition.getField().replace(".", "_"):queryCondition.getField());
if(queryCondition.getOperator().equals(QueryCondition.LK)) {
query.setParameter(queryCondition.getField(), "%"+queryCondition.getValue()+"%");
}else {
query.setParameter(queryCondition.getField(), queryCondition.getValue());
}
}
}
}
}
return query;
}
@Override
public int executeNativeQuerySql(String sql) {
Query query = em.createNativeQuery(sql);
return query.executeUpdate();
}
@Override
public void flush() {
em.flush();
}
@Override
public void clear() {
em.clear();
}
@Override
public void refresh(Object entity) {
em.refresh(entity);
}
}
3、通用分页类:Pagination
import java.io.Serializable;
import java.util.List;
/**
* 分页结果对象
* <pre>
* 如果是分页查询,返回的结果请用该分页对象封装
* </pre>
*/
public class Pagination<T> implements Serializable {
private static final long serialVersionUID = 5104811017362151385L;
/**当前页*/
private int currentPage;
/**每页显示记录数*/
private int pageSize;
/**总记录数*/
private long recordCount = 1L;
/**记录集合*/
private List<T> recordList;
/**总页数*/
private int pageCount;
/**偏移数*/
private int offset;
/**上一页*/
private int prePage;
/**下一页*/
private int nextPage;
/**是否有上一页*/
private boolean hasPrePage;
/**是否有下一页*/
private boolean hasNextPage;
/**
* 默认的空参构造数
*
*/
public Pagination() {
}
/**
* 构造函数,计算总页数、是否有上一页、下一页等.
* @param currentPage int 当前页
* @param pageSize int 每页显示记录数
* @param recordCount long 总记录数
* @param recordList List<T> 记录集合
*/
public Pagination(int currentPage, int pageSize, long recordCount, List<T> recordList) {
this.currentPage = currentPage;
if(currentPage < 1) {
this.currentPage = 1;
}
this.pageSize = pageSize;
this.recordCount = recordCount;
this.recordList = recordList;
//上一页等于当前页减一
this.prePage = this.currentPage - 1;
if(this.prePage < 1) {
this.hasPrePage = false;//没有上一页
this.prePage = 1;
}else {
this.hasPrePage = true;//有上一页
}
//计算总页数
this.pageCount = (int)Math.ceil(recordCount / (double)pageSize);
if(this.currentPage > this.pageCount) {
this.currentPage = this.pageCount;
}
//下一页等于当前页加一
this.nextPage = this.currentPage + 1;
if(this.nextPage > this.pageCount) {
this.hasNextPage = false;//没有下一页
this.nextPage = this.pageCount;
}else {
this.hasNextPage = true;//有下一页
}
//偏移量
this.offset = (this.currentPage - 1) * pageSize;
}
}
4、通用查询条件类:QueryCondition
/**
* jpql查询条件对象
* <pre>
* 根据jpql的查询语法,把每个条件的操作封装成一个查询对象
* </pre>
*/
public class QueryCondition {
/**等于*/
public static final String EQ = "=";
/**小于*/
public static final String LT = "<";
/**大于*/
public static final String GT = ">";
/**小于等于*/
public static final String LE = "<=";
/**大于等于*/
public static final String GE = ">=";
/**相似*/
public static final String LK = "like";
/**
* @TODO 可以再扩展
*/
/**自定义jpql语句*/
public static final String CUSTOM = "custom";
/**属性名*/
private String field;
/**操作符*/
private String operator;
/**值*/
private Object value;
/**自定义jpql语句*/
private String customJPQL;
/**
* 构造方法
* 传入自定义语句
* @param customJPQL
*/
public QueryCondition(String customJPQL) {
this.customJPQL = customJPQL;
this.operator = CUSTOM;
}
/**
* 构造方法
* @param field String 属性名
* @param operatorString 操作符
* @param value Object 值 如果属性是日期类型,需将字符串格式为日期 如new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-03-23 10:22:22")
*/
public QueryCondition(String field, String operator, Object value) {
this.field = field;
this.operator = operator;
this.value = value;
}
}
5、通用服务接口:HibernateBaseService
public interface HibernateBaseService<T> extends HibernateBaseDao<T> {
}
6、通用服务接口实现类:HibernateBaseServiceImpl
@Transactional(rollbackFor = { BaseException.class, RuntimeException.class, Error.class })
public class HibernateBaseServiceImpl<T> extends HibernateBaseDaoImpl<T> implements HibernateBaseService<T>{
}