无Spring环境下仅用Hibernate如何实现类似JpaRepository/CrudRepository的通用CRUD功能?
基于Hibernate实现通用泛型DAO的方案
步骤1:定义通用泛型BaseDao接口
接口定义所有通用CRUD方法,泛型参数T为实体类型,ID为主键类型,适配不同实体的主键差异。
import java.util.List; public interface BaseDao<T, ID> { T findById(ID id); void save(T entity); void update(T entity); void delete(T entity); List<T> findAll(); }
步骤2:实现BaseDao抽象基类,封装所有通用CRUD逻辑
抽象基类实现BaseDao接口,通过反射获取实际操作的实体Class,解决泛型擦除问题,所有通用方法仅在这里实现一次即可,子类无需重复编写。同时统一使用try-with-resources管理Session,避免资源泄露。
import org.hibernate.Session; import org.hibernate.Transaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.lang.reflect.ParameterizedType; import java.util.List; public abstract class BaseDaoImpl<T, ID> implements BaseDao<T, ID> { private static final Logger log = LogManager.getLogger(BaseDaoImpl.class); private final Class<T> entityClass; // 构造方法通过反射获取实际的实体Class类型 @SuppressWarnings("unchecked") public BaseDaoImpl() { ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); this.entityClass = (Class<T>) pt.getActualTypeArguments()[0]; } @Override public T findById(ID id) { try (Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession()) { return session.get(entityClass, id); } catch (Exception e) { log.error("查询实体失败", e); return null; } } @Override public void save(T entity) { Transaction transaction = null; try (Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession()) { transaction = session.beginTransaction(); session.save(entity); transaction.commit(); } catch (Exception e) { log.error("保存实体失败", e); if (transaction != null) transaction.rollback(); } } @Override public void update(T entity) { Transaction transaction = null; try (Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession()) { transaction = session.beginTransaction(); session.update(entity); transaction.commit(); } catch (Exception e) { log.error("更新实体失败", e); if (transaction != null) transaction.rollback(); } } @Override public void delete(T entity) { Transaction transaction = null; try (Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession()) { transaction = session.beginTransaction(); session.delete(entity); transaction.commit(); } catch (Exception e) { log.error("删除实体失败", e); if (transaction != null) transaction.rollback(); } } @Override public List<T> findAll() { try (Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession()) { return session.createQuery("FROM " + entityClass.getSimpleName(), entityClass).list(); } catch (Exception e) { log.error("查询所有实体失败", e); return List.of(); } } }
步骤3:业务DAO仅需继承基类,无需重复实现CRUD
以UserDao为例:
业务DAO接口
// 直接继承BaseDao,指定实体类型和主键类型即可,有自定义方法再单独加 public interface UserDao extends BaseDao<User, Integer> { // 如果有通用CRUD之外的特殊查询方法,在这里定义即可 }
业务DAO实现类
// 继承BaseDaoImpl,实现UserDao接口,无需重写任何通用CRUD方法 public class UserDaoImpl extends BaseDaoImpl<User, Integer> implements UserDao { // 如果有自定义方法,在这里实现即可 }
以VpnDao为例:
VpnDao接口
public interface VpnDao extends BaseDao<Vpn, Byte> { }
VpnDao实现类
public class VpnDaoImpl extends BaseDaoImpl<Vpn, Byte> implements VpnDao { }
方案优势
- 所有通用CRUD逻辑仅在BaseDaoImpl中实现一次,20+业务DAO无需重复编写相同代码,后续新增DAO仅需几行核心代码即可完成
- 自动适配不同实体类型和主键类型,灵活性高
- 统一Session资源管理、事务处理、异常日志,避免各实现类逻辑不一致的问题
- 完全基于Hibernate原生能力,无需引入Spring等额外框架
内容的提问来源于stack exchange,提问作者Alexey Zhukov
相关产品推荐
相关产品推荐

