如何使用泛型实现 Hibernate DAO

How to implement Hibernate DAO with generics

我找到了一些关于如何使用泛型构建 Hibernate DAO 的教程,但它们都使用 EntityManager 而不是 SessionFactory。我的问题是如何使用 SessionFactory 构建带有泛型的 DAO。到目前为止我有以下内容:

接口:

public interface GenericDao<T> {

    public void save(T obj);
    public void update(T obj);
    public void delete(T obj);
    public T findById(long id);
}

Class:

@Repository
public class GenericDaoImpl<T> implements GenericDao<T> {

    @Autowired
    private SessionFactory sessionFactory;

    public void save(T obj) {
        Session session = sessionFactory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.save(obj);
            tx.commit();
        } catch (HibernateException e) {
            if(tx != null)
                tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

    public void update(T obj) {
        Session session = sessionFactory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.update(obj);
            tx.commit();
        } catch (HibernateException e) {
            if(tx != null)
                tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

    public void delete(T obj) {
        Session session = sessionFactory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.delete(obj);
            tx.commit();
        } catch (HibernateException e) {
            if(tx != null)
                tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

    public T findById(long id) {
        // ??
        return null;
    }

我不确定如何 findById 使用泛型。我相信其他的方法都是对的,如果我错了请指正。

附带问题: 使用 EntityManager 是否比使用 SessionFactory 更有益?我看到了一些关于这个主题的帖子,但还想听听更多的意见。

您需要从该方法中访问 Class<T>。您有两个选择,您可以将 Class<T> 传递到方法中:

public T findById(long id, Class<T> clazz) {
    // method implementation
}

或者您可以将 Class<T> 传递到 class 的构造函数中以在方法中使用:

@Repository
public class GenericDaoImpl<T> implements GenericDao<T> {

    private Class<T> clazz;

    protected GenericDaoImpl(Class<T> clazz) {
        this.clazz = clazz;
    }

    // other methods omitted

    public T findById(long id) {
        // method implementation
    }
}

而 subclasses 会将它们的 class 传递给 superclass:

public class UserDao extends GenericDaoImpl<User> {
    public UserDao() {
        super(User.class);
    }
}

然后,使用您的 clazz 实例,您可以使用 Session#get 方法在通用方法中获取实体:

T entity = session.get(clazz, id);

有关详细信息,请参阅以下问题:

  • How to get a class instance of generics type T
  • Get object by ID in Hibernate

至于附带问题,EntityManager 是 JPA 的一部分(Java 持久性 API)。使用 Java API 规范而不是 Hibernate API 开发您的应用程序可以让您的应用程序不依赖于 Hibernate。这允许您在 Hibernate、OpenJPA 或 TopLink 等流行的 JPA 实现之间切换,而无需对代码进行更改。

This question 有更多关于差异的信息。