【问题标题】:Hibernate: CRUD Generic DAO休眠:CRUD 通用 DAO
【发布时间】:2012-04-01 01:24:21
【问题描述】:

我的 Web 应用程序有很多服务表/实体,例如 payment_methodstax_codesprovince_codes 等。

每次我添加一个新实体时,我都必须编写一个 DAO。问题是,基本上,它们都是一样的,但唯一的区别是实体类本身

我知道 Hibernate 工具可以自动为我生成代码,但我现在不能使用它们(不要问为什么),所以我正在考虑一个 通用 DAO。有很多关于这方面的文献,但我无法将其拼凑在一起并使其与 Spring 一起使用。

我认为这都是关于泛型的,它将有四种基本方法:

  • listAll
  • saveOrUpdate
  • deleteById
  • getById

仅此而已。


问题:

不重新发明轮子的最佳实践是什么?还没有准备好使用的东西吗?

【问题讨论】:

  • 在 google 上的结果为 1 code.google.com/p/hibernate-generic-dao,这应该为您提供了一个良好的基础。这是另一个:ibm.com/developerworks/java/library/j-genericdao/index.html
  • 注意:各位开发者,截至 2011 年 12 月,我目前不支持这个项目。我从一开始就是这个项目的唯一所有者,但我将不再跟进问题或发布。在这一点上,没有其他人可以承担这一责任,所以它不会发生。仍然有一些用户在 Google 群组上回复。我带来的不便表示歉意。 ...
  • 取自首页............你认为它可靠吗? :-)
  • ye gads man,google 上的选项 4 怎么样。即使它不受支持,您也可以将其用作指南。

标签: java spring hibernate generics dao


【解决方案1】:

这是我的

@Component
public class Dao{

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory;

    public <T> T save(final T o){
      return (T) sessionFactory.getCurrentSession().save(o);
    }


    public void delete(final Object object){
      sessionFactory.getCurrentSession().delete(object);
    }

    /***/
    public <T> T get(final Class<T> type, final Long id){
      return (T) sessionFactory.getCurrentSession().get(type, id);
    }

    /***/
    public <T> T merge(final T o)   {
      return (T) sessionFactory.getCurrentSession().merge(o);
    }

    /***/
    public <T> void saveOrUpdate(final T o){
      sessionFactory.getCurrentSession().saveOrUpdate(o);
    }

    public <T> List<T> getAll(final Class<T> type) {
      final Session session = sessionFactory.getCurrentSession();
      final Criteria crit = session.createCriteria(type);
  return crit.list();
    }
// and so on, you shoudl get the idea

然后你就可以在服务层这样访问了:

 @Autowired
    private Dao dao;

   @Transactional(readOnly = true)
    public List<MyEntity> getAll() {
      return dao.getAll(MyEntity.class);
    }

【讨论】:

  • 1) 你能用 spring xml bean 配置来编辑你的答案吗?
  • @NimChimpsky 为什么你使用SessionFactory 而不是EntityManager?哪种方法更好?
  • 如果不是我所有的表都有 long 作为 id 怎么办?
  • @Jumi 他们可能应该拥有
  • @NimChimpsky 是的,我是这样的。但我更喜欢通用存储库的想法。像这样:public class UserRepository extends AbstractRepository&lt;User,Long&gt;。尽管可以在 weblogic 容器中使用,但我找不到解决方案。那就是说我来自 php symfony,只是开始了解 java 和 java ee。也许 symfony 约定让我认为这是更好的方式。
【解决方案2】:

Spring Data JPA 是一个很棒的项目,它可以为你生成 DAO 等等!您只需创建一个接口(无需任何实现):

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {}

这个接口(通过继承JpaRepository)会自动给你:

PaymentMethod save(PaymentMethod entity);
Iterable<PaymentMethod> save(Iterable<? extends PaymentMethod> entities);
PaymentMethod findOne(Integer id);
boolean exists(Integer id);
Iterable<PaymentMethod> findAll();
long count();
void delete(Integer id);
void delete(PaymentMethod entity);
void delete(Iterable<? extends PaymentMethod> entities);
void deleteAll();
Iterable<PaymentMethod> findAll(Sort sort);
Page<PaymentMethod> findAll(Pageable pageable);
List<PaymentMethod> findAll();
List<PaymentMethod> findAll(Sort sort);
List<PaymentMethod> save(Iterable<? extends PaymentMethods> entities);
void flush();
PaymentMethod saveAndFlush(PaymentMethods entity);
void deleteInBatch(Iterable<PaymentMethods> entities);

接口是强类型(泛型)并自动为您实现。对于每个实体,您所要做的就是创建一个扩展 JpaRepository&lt;T,Integer extends Serializable&gt; 的接口。

但是等等,还有更多!假设您的 PaymentMethod 具有 namevalidSince 持久字段。如果你在你的界面中添加以下方法:

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {

  Page<PaymentMethod> findByNameLikeAndValidSinceGreaterThan(
    String name, Date validSince, Pageable page
  );

}

框架会解析方法名:

findBy名字喜欢)AndValidSince大于)

创建 JPA QL 查询,应用分页和排序 (Pageable page) 并为您运行它。无需实现:

paymentMethodsDao.findByNameLikeAndValidSinceGreaterThan(
  "abc%",
  new Date(),
  new PageRequest(0, 20, Sort.Direction.DESC, "name"
);

查询结果:

SELECT *  //or COUNT, framework also returns the total number of records
FROM PaymentMethods
WHERE name LIKE "abc%"
  AND validSince > ...

并且应用了分页。

唯一的缺点是这个项目比较新,而且比较容易上手(但它的开发非常活跃)。

【讨论】:

  • 嗨,你能展示一个 sn-p,你在哪里使用 PaymentMethodsDao 实现?我不知道如何获得一个运行示例如何使用这个界面......谢谢!
  • @MarioDavid:您只需将PaymentMethodsDao 注入您的其他bean 并使用它。 Spring 会为你实现它。
【解决方案3】:

不要为每个实体编写特定的 dao。您可以实现一个通用 DAO,为您需要的所有实体完成 90% 的工作。如果您希望对某些实体进行特定处理,可以对其进行扩展。

在我目前正在从事的项目中,我们有这样的 DAO,它包装了 Hibernate 会话,提供了与您描述的方法类似的方法。此外,我们正在使用 ISearch API - 托管在 google 代码上的开源项目,并为 Hibernate 和 JPA 提供非常方便的标准构建接口。

【讨论】:

    【解决方案4】:

    您可以使用通用 DAO 作为其他特定于域的 DAO 类的杠杆。假设您有一个 Employee Domain 类:

      @Entity
      @Table(name="employee")
      public class Employee {
    
        @Id
        @Column(name="id")
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
    
        @Column(name="emp_name")
        private String empName;
    
        @Column(name="emp_designation")
        private String empDesignation;
    
        @Column(name="emp_salary")
        private Float empSalary;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getEmpName() {
            return empName;
        }
    
        public void setEmpName(String empName) {
            this.empName = empName;
        }
    
        public String getEmpDesignation() {
            return empDesignation;
        }
    
        public void setEmpDesignation(String empDesignation) {
            this.empDesignation = empDesignation;
        }
    
        public Float getEmpSalary() {
            return empSalary;
        }
    
        public void setEmpSalary(Float empSalary) {
            this.empSalary = empSalary;
        }
    
    
    }
    

    那么所需的通用 DAO 将如下所示:

    通用 DAO 接口:

     public interface GenericRepositoryInterface<T> {
    
        public T save(T emp);
        public Boolean delete(T emp);
        public T edit(T emp);
        public T find(Long empId);
    }
    

    通用 DAO 实现:

    @Repository
    public class GenericRepositoryImplementation<T> implements GenericRepositoryInterface<T> {
    
    protected EntityManager entityManager;
    private Class<T> type;
    
    public GenericRepositoryImplementation() {
        // TODO Auto-generated constructor stub
    
    }
    
    public GenericRepositoryImplementation(Class<T> type) {
        // TODO Auto-generated constructor stub
    
        this.type = type;
    }
    
    public EntityManager getEntityManager() {
        return entityManager;
    }
    
    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    @Override
    public T save(T emp) {
        // TODO Auto-generated method stub
        entityManager.persist(emp);
        entityManager.flush();
        return emp;
    }
    
    @Override
    public Boolean delete(T emp) {
        // TODO Auto-generated method stub
        try {
             entityManager.remove(emp);
        } catch (Exception ex) {
            return false;
        }
        return true;
    }
    
    @Override
    public T edit(T emp) {
        // TODO Auto-generated method stub
        try{
           return entityManager.merge(emp);
        } catch(Exception ex) {
            return null;
        }
    }
    
    @Override
    public T find(Long empId) {
        // TODO Auto-generated method stub
        return (T) entityManager.find(Employee.class, empId);
    }
    } 
    

    然后,每个特定于域的 DAO 类都需要扩展这个通用 DAO 类。域特定的 DAO 类甚至可以为一般不常见的操作实现另一个接口。并且更喜欢使用构造函数发送类型信息。

    【讨论】:

    • 为什么不使用第一个例子然后继承它?
    • 如果我理解正确,你的意思是说继承 GenericRepositoryImplementation。这就是要做的事情。现在,Employee 特定的 DAO 必须从 GenericRepositoryImplementation 类继承公共方法,除了实现自己的接口。
    【解决方案5】:

    您可以创建一个 baseDAO 接口和一个 baseDAO 实现类。 当您需要具有不同类类型的特定用例时,您可以创建该类的 DAO,它继承 baseDAO 类并根据该类的特定需求实现额外的接口,如下所示

    IBaseDAO

     public interface IBaseDAO<T> {
    
    /**
     * @Purpose :Save object of type T
     * @param transientInstance
     */
    public Object persist(final T transientInstance);
    
    /**
     * @Purpose :Delete object of type T
     * @param persistentInstance
     */
    public void remove(final T persistentInstance);
    
    /**
     * @Purpose :Update Object of type T
     * @param detachedInstance
     * @return
     */
    public T merge(final T detachedInstance);
    
    /**
     * @Purpose :Find object by 'id' of type T
     * @param identifier
     * @return
     */
    public T findById(final Long identifier, Class<?> persistClass);
    }
    

    BaseDAO 类

    public class BaseDAO<T> implements IBaseDAO<T> {
    
    @Autowired
    private SessionFactory sessionFactory;
    
    public Object persist(T entity) {
        return this.getSession().save(entity);
    }
    
    @Override
    public void remove(T persistentInstance) {
        this.getSession().delete(persistentInstance);
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public T merge(T detachedInstance) {
        return (T) this.getSession().merge(detachedInstance);
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public T findById(Long identifier, Class<?> persistClass) {
        return (T) this.getSession().get(persistClass, identifier);
    }
    
    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
    public Session getSession() {
        return getSessionFactory().getCurrentSession();
    }
    
    }
    

    和具体的界面

    public interface IUserDAO extends IBaseDAO<User> {
    
       public User getUserById(long userId);
    
       public User findUserByUsername(String username);
    
    }
    

    和这样的类

    @Repository("userDAO")
    public class UserDAO extends BaseDAO<User> implements IUserDAO {
    
    public User getUserById(long userId) {
        return findById(userId, User.class);
    }
    
    @Override
        public User findUserByUsername(String username) {
            Criteria criteria = getSession().createCriteria(User.class);
            criteria.add(Restrictions.eq("username", username));
            return (User) criteria.uniqueResult();
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 2018-01-14
      相关资源
      最近更新 更多