The DAO with Spring and Hibernate – 使用Spring和Hibernate的DAO

最后修改: 2011年 12月 2日

1. Overview

1.概述

This article will show how to implement the DAO with Spring and Hibernate. For the core Hibernate configuration, check out the previous Hibernate 5 with Spring article.

本文将介绍如何使用 Spring 和 Hibernate 实现 DAO。有关 Hibernate 的核心配置,请查看之前的 Hibernate 5 with Spring 文章。

2. No More Spring Templates

2.不再有春天的模板

Starting Spring 3.0 and Hibernate 3.0.1, the Spring HibernateTemplate is no longer necessary to manage the Hibernate Session. It’s now possible to make use of contextual sessionssessions managed directly by Hibernate and active throughout the scope of a transaction.

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

As a consequence, it’s now best practice to use the Hibernate API directly instead of the HibernateTemplate. This will effectively decouple the DAO layer implementation from Spring entirely.

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

2.1. Exception Translation Without the HibernateTemplate

2.1.不使用HibernateTemplate的异常翻译

Exception Translation was one of the responsibilities of HibernateTemplate – translating the low-level Hibernate exceptions to higher level, generic Spring exceptions.

异常翻译是HibernateTemplate的职责之一–将低级别的Hibernate异常翻译成高级别的、通用的Spring异常。

Without the template, this mechanism is still enabled and active for all the DAOs annotated with the @Repository annotation. Under the hood, this uses a Spring bean postprocessor that will advise all @Repository beans with all the PersistenceExceptionTranslator found in the Spring context.

在没有模板的情况下,这种机制仍然是有效的 对于所有用@Repository注解的DAO。在引擎盖下,这使用了一个 Spring Bean 后处理器,它将用在 Spring 上下文中发现的所有 @Repository Bean 的 PersistenceExceptionTranslator 给予建议。

One thing to remember is that exception translation uses proxies. For Spring to be able to create proxies around the DAO classes, these must not be declared as final.

需要记住的一点是,异常翻译使用代理。为了让Spring能够围绕DAO类创建代理,这些代理必须不被声明为final

2.2. Hibernate Session Management Without the Template

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

When Hibernate support for contextual sessions came out, the HibernateTemplate essentially became obsolete. In fact, the Javadoc of the class now highlights this aspect (bold from the original):

当Hibernate对上下文会话的支持出来后,HibernateTemplate基本上就过时了。事实上,该类的Javadoc现在强调了这个方面(从原来的粗体)。

NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can also be coded in plain Hibernate style. Hence, for newly started projects, consider adopting the standard Hibernate3 style of coding data access objects instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.

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

3. The DAO

3.DAO

We’ll start with the base DAO – an abstract, parametrized DAO which supports the common generic operations and that we can extend for each entity:

我们将从基础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();
    }
}

A few aspects are interesting here – as discussed, the abstract DAO doesn’t extend any Spring template (such as HibernateTemplate). Instead, the Hibernate SessionFactory is injected directly in the DAO, and will have the role of the main Hibernate API, through the contextual Session it exposes:

这里有几个方面很有意思–正如所讨论的,抽象的DAO并没有扩展任何Spring模板(如HibernateTemplate)。相反,HibernateSessionFactory被直接注入DAO中,并将通过其暴露的上下文Session发挥主要Hibernate API的作用。

this.sessionFactory.getCurrentSession();

this.sessionFactory.getCurrentSession();

Also, note that the constructor receives the Class of the entity as a parameter to be used in the generic operations.

另外,请注意,构造函数接收实体的Class作为参数,以便在泛型操作中使用。

Now, let’s look at an example implementation of this DAO, for a Foo entity:

现在,让我们看看这个DAO的一个实现例子,对于一个Foo实体。

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

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

4. Conclusion

4.结论

This article covered the configuration and implementation of the persistence layer with Hibernate and Spring.

这篇文章介绍了用Hibernate和Spring配置和实现持久层的情况。

The reasons to stop relying on templates for the DAO layer was discussed, as well as possible pitfalls of configuring Spring to manage transactions and the Hibernate Session. The final result is a lightweight, clean DAO implementation, with almost no compile-time reliance on Spring.

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

The implementation of this simple project can be found in the github project.

这个简单项目的实现可以在github 项目中找到。