使用Spring和Hibernate的DAO

2023/05/18

1. 概述

本文将展示如何使用 Spring 和 Hibernate 实现 DAO。对于核心 Hibernate 配置,请查看之前的Hibernate 5 with Spring文章。

2. 不再有 Spring 模板

从 Spring 3.0 和 Hibernate 3.0.1 开始,不再需要Spring HibernateTemplate来管理 Hibernate Session。现在可以使用上下文会话——由 Hibernate 直接管理并在整个事务范围内处于活动状态的会话。

因此,现在最好的做法是直接使用 Hibernate API 而不是HibernateTemplate。这将有效地将 DAO 层实现与 Spring 完全分离。

2.1. 没有HibernateTemplate的异常转换

异常转换是HibernateTemplate的职责之一——将低级别的 Hibernate 异常转换为更高级别的通用 Spring 异常。

在没有模板的情况下,对于所有使用 @Repository 注解进行注解的 DAO ,此机制仍然启用并处于活动状态 。在引擎盖下,这使用了一个 Spring bean 后处理器,它将使用在 Spring 上下文中找到的所有PersistenceExceptionTranslator通知所有@Repository bean 。

要记住的一件事是异常转换使用代理。为了让 Spring 能够围绕 DAO 类创建代理,这些不能声明为final。

2.2. 没有模板的 Hibernate 会话管理

当 Hibernate 对上下文会话的支持出现时,HibernateTemplate基本上已经过时了。事实上,该类的 Javadoc 现在突出显示了这一方面(粗体来自原文):

注意:从 Hibernate 3.0.1 开始,事务性 Hibernate 访问代码也可以以普通 Hibernate 样式进行编码。因此,对于新开始的项目,考虑采用标准的 Hibernate3 风格来编码数据访问对象,基于 {@link org.hibernate.SessionFactory#getCurrentSession()}。

3. The DAO

我们将从基础 DAO 开始——一个抽象的、参数化的 DAO,它支持常见的通用操作,我们可以为每个实体扩展它:

public abstract class AbstractHibernateDao<T extends Serializable> {
    private Class<T> clazz;

    @Autowired
    protected SessionFactory sessionFactory;

    public final void setClazz(final Class<T> clazzToSet) {
        clazz = Preconditions.checkNotNull(clazzToSet);
    }

    // API
    public T findOne(final long id) {
        return (T) getCurrentSession().get(clazz, id);
    }

    public List<T> findAll() {
        return getCurrentSession().createQuery("from " + clazz.getName()).list();
    }

    public T create(final T entity) {
        Preconditions.checkNotNull(entity);
        getCurrentSession().saveOrUpdate(entity);
        return entity;
    }

    public T update(final T entity) {
        Preconditions.checkNotNull(entity);
        return (T) getCurrentSession().merge(entity);
    }

    public void delete(final T entity) {
        Preconditions.checkNotNull(entity);
        getCurrentSession().delete(entity);
    }

    public void deleteById(final long entityId) {
        final T entity = findOne(entityId);
        Preconditions.checkState(entity != null);
        delete(entity);
    }

    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
}

这里有几个方面很有趣——正如所讨论的,抽象 DAO 不扩展任何 Spring 模板(例如HibernateTemplate)。相反,Hibernate SessionFactory直接注入到 DAO 中,并将通过它公开的上下文Session发挥主要 Hibernate API 的作用:

这个.sessionFactory.getCurrentSession();

另请注意,构造函数接收实体的类作为要在通用操作中使用的参数。

现在,让我们看一下这个 DAO 的示例实现,用于Foo实体:

@Repository
public class FooDAO extends AbstractHibernateDAO< Foo > implements IFooDAO{

   public FooDAO(){
      setClazz(Foo.class );
   }
}

4. 总结

本文介绍了使用 Hibernate 和 Spring 的持久层的配置和实现。

讨论了停止依赖 DAO 层模板的原因,以及配置 Spring 来管理事务和 Hibernate Session 的可能陷阱。最终结果是一个轻量级、干净的 DAO 实现,几乎没有编译时对 Spring 的依赖。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章