DAO泛型使用

来源:互联网 发布:有做标书软件 编辑:程序博客网 时间:2024/06/15 01:03

这是一个来自CaveatEmptor实例应用,在JDK5.0下实现的DAO模式. 这个模式在Java Persistence With Hibernate里面也有讲到. 另外有两个链接,可能会对你有用,Sessions and transactions 和Open Session in View.

这次的DAO例子是基于接口的.很多工具, 像Hibernate已经提供了数据库的便携访问,所以我们不是为持久层的轻便而设计接口. 然而, DAO接口在较为复杂的应用中更有意义, 当有几个持久化服务被封装到一个持久层的时候, 我想在很多情况下你应该直接使用Hibernate或者JPA, 而使用外加的DAO层最好的理由是为了实现更高的抽象化(例如:定义方法名getMaximumBid()而不是无数次地重复 session.createQuery(...)).

DAO接口

每一个持久化实体我用一个接口, 另外还有一个定义了泛型CRUD(增,删,改,查)操作的顶层接口.

Java代码
  1. public interface GenericDAO<T, IDextends Serializable> {  
  2.   
  3.      T findById(ID id, boolean lock);  
  4.   
  5.      List<T> findAll();  
  6.   
  7.      List<T> findByExample(T exampleInstance);  
  8.   
  9.      T makePersistent(T entity);  
  10.   
  11.     void makeTransient(T entity);  
  12. }  
public interface GenericDAO<T, ID extends Serializable> {    
  T findById(ID id, boolean lock);    
  List<T> findAll();   
   List<T> findByExample(T exampleInstance); 
     T makePersistent(T entity);    
  void makeTransient(T entity); }


你已经可以看到这将是一个"面向状态",具有像makePersistent()和makeTransient()方法的数据访问API.而且, 你必须提供一个类型和一个标识参数(这里指的是持久化对象的标识符-Object Identifier),对于大多数的持久化解决方案,标识符类型必须是Serializable的.

以下是提供了类型参数关于某一实体的DAO接口,它继承了泛型接口:

Java代码
  1. public interface ItemDAOextends GenericDAO<Item, Long> {  
  2.   
  3.     public staticfinal String QUERY_MAXBID = "ItemDAO.QUERY_MAXBID";  
  4.     public staticfinal String QUERY_MINBID = "ItemDAO.QUERY_MINBID";  
  5.   
  6.      Bid getMaxBid(Long itemId);  
  7.      Bid getMinBid(Long itemId);  
  8.   
  9. }  
public interface ItemDAO extends GenericDAO<Item, Long> {   
   public static final String QUERY_MAXBID = "ItemDAO.QUERY_MAXBID";  
   public static final String QUERY_MINBID = "ItemDAO.QUERY_MINBID";    
  Bid getMaxBid(Long itemId);     Bid getMinBid(Long itemId); 
 }


基本上我们把通用的CRUD操作和具体业务相关的数据访问操作都分开了.(暂且不用理上面接口中的常量,如果使用Annotation,他们将会 很有用.)然而,即使对于具体某个实体你只需要这些通用的CRUD操作,你也应该为它单独写一个接口.即使这个接口是空的.在你的controller code(控制器/业务代码)中使用一个具体的DAO是很重要的.否则当你要为这个实体引入具体的数据访问操作的时候,你将面临重构的问题.

一个Hibernate的(泛型DAO)实现
任何一个"可管理状态"的持久化服务都可以实现上面的泛型接口.首先,我们用Hibernate来实现这些泛型CRUD

Java代码
  1. public abstractclass GenericHibernateDAO<T, ID extends Serializable>  
  2.         implements GenericDAO<T, ID> {  
  3.   
  4.     private Class<T> persistentClass;  
  5.     private Session session;  
  6.   
  7.     public GenericHibernateDAO() {  
  8.         this.persistentClass = (Class<T>) ((ParameterizedType) getClass()  
  9.                                  .getGenericSuperclass()).getActualTypeArguments()[0];  
  10.       }  
  11.   
  12.     @SuppressWarnings("unchecked")  
  13.     public void setSession(Session s) {  
  14.         this.session = s;  
  15.      }  
  16.   
  17.     protected Session getSession() {  
  18.         if (session == null)  
  19.             throw new IllegalStateException("Session has not been set on DAO before usage");  
  20.         return session;  
  21.      }  
  22.   
  23.     public Class<T> getPersistentClass() {  
  24.         return persistentClass;  
  25.      }  
  26.   
  27.     @SuppressWarnings("unchecked")  
  28.     public T findById(ID id, boolean lock) {  
  29.          T entity;  
  30.         if (lock)  
  31.              entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);  
  32.         else  
  33.              entity = (T) getSession().load(getPersistentClass(), id);  
  34.   
  35.         return entity;  
  36.      }  
  37.   
  38.     @SuppressWarnings("unchecked")  
  39.     public List<T> findAll() {  
  40.         return findByCriteria();  
  41.      }  
  42.   
  43.     @SuppressWarnings("unchecked")  
  44.     public List<T> findByExample(T exampleInstance, String[] excludeProperty) {  
  45.          Criteria crit = getSession().createCriteria(getPersistentClass());  
  46.          Example example =   Example.create(exampleInstance);  
  47.         for (String exclude : excludeProperty) {  
  48.              example.excludeProperty(exclude);  
  49.          }  
  50.          crit.add(example);  
  51.         return crit.list();  
  52.      }  
  53.   
  54.     @SuppressWarnings("unchecked")  
  55.     public T makePersistent(T entity) {  
  56.          getSession().saveOrUpdate(entity);  
  57.         return entity;  
  58.      }  
  59.   
  60.     public void makeTransient(T entity) {  
  61.          getSession().delete(entity);  
  62.      }  
  63.   
  64.     public void flush() {  
  65.          getSession().flush();  
  66.      }  
  67.   
  68.     public void clear() {  
  69.          getSession().clear();  
  70.      }  
  71.   
  72.     /**
  73.       * Use this inside subclasses as a convenience method.
  74.       */  
  75.     @SuppressWarnings("unchecked")  
  76.     protected List<T> findByCriteria(Criterion... criterion) {  
  77.          Criteria crit = getSession().createCriteria(getPersistentClass());  
  78.         for (Criterion c : criterion) {  
  79.              crit.add(c);  
  80.          }  
  81.         return crit.list();  
  82.     }  
  83.   
  84. }  
public abstract class GenericHibernateDAO<T, ID extends Serializable>        
 implements GenericDAO<T, ID> {   
   private Class<T> persistentClass;   
  private Session session;   
   public GenericHibernateDAO() {  
       this.persistentClass = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0];   
   }      
@SuppressWarnings("unchecked")  
   public void setSession(Session s) {      
   this.session = s;   
  }  
    protected Session getSession() { 
        if (session == null)  throw new IllegalStateException("Session has not been set on DAO before usage"); 
        return session;     }   
   public Class<T> getPersistentClass() { 
        return persistentClass;    
 }    
  @SuppressWarnings("unchecked")  
   public T findById(ID id, boolean lock) {   
      T entity;  
       if (lock)             entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);       
  else             entity = (T) getSession().load(getPersistentClass(), id);   
       return entity; 
  }      
@SuppressWarnings("unchecked")     public List<T> findAll() {   
      return findByCriteria();  
   }    
  @SuppressWarnings("unchecked")     
public List<T> findByExample(T exampleInstance, String[] excludeProperty) {
         Criteria crit = getSession().createCriteria(getPersistentClass());   
      Example example =  Example.create(exampleInstance);      
   for (String exclude : excludeProperty) {    
         example.excludeProperty(exclude);      
   }       
  crit.add(example);    
     return crit.list();    
 }      
@SuppressWarnings("unchecked")
     public T makePersistent(T entity) {  
       getSession().saveOrUpdate(entity);   
      return entity;  
   }     
 public void makeTransient(T entity) {   
      getSession().delete(entity);  
   }      public void flush() { 
        getSession().flush();    
 }   
   public void clear() { 
        getSession().clear();  
   }    
  /**   
   * Use this inside subclasses as a convenience method.  
    */    
 @SuppressWarnings("unchecked")   
  protected List<T> findByCriteria(Criterion... criterion) { 
        Criteria crit = getSession().createCriteria(getPersistentClass());      
   for (Criterion c : criterion) {        
     crit.add(c);    
     }     
    return crit.list();  
  }  }

 


在这个实现里面有几个有趣的东西. 第一,很明显它需要一个Sesssion来支撑,并且为这个Session提供了Setter注入.也可以用构造方法注入.你怎么设置Session或者 这个Session的作用域(Scope,在这里应该是指Session的生命周期,接下来将它翻译作"生命周期"),都跟具体的DAO实现无关.DAO 不应该控制事务或者Session的生命周期.

我们需要禁止一些未检查转换(unchecked casts)编译时警告.因为Hibernate的接口是基于JDK1.4的.接下来是泛型CRUD操作的实现,很简单,最后一个方法(设计得)很好,它 用了另一个JDK5.0的新特性-varargs(不定参数),它帮助我们在具体实体DAO里面创建Criteria查询.下面是一个继承了用 Hibernate实现的泛型DAO的具体DAO例子:

Java代码
  1. public class ItemDAOHibernate  
  2.         extends      GenericHibernateDAO<Item, Long>  
  3.         implements   ItemDAO {  
  4.   
  5.     public Bid getMaxBid(Long itemId) {  
  6.          Query q = getSession().getNamedQuery(ItemDAO.QUERY_MAXBID);  
  7.          q.setParameter("itemid", itemId);  
  8.         return (Bid) q.uniqueResult();  
  9.      }  
  10.   
  11.     public Bid getMinBid(Long itemId) {  
  12.          Query q = getSession().getNamedQuery(ItemDAO.QUERY_MINBID);  
  13.          q.setParameter("itemid", itemId);  
  14.         return (Bid) q.uniqueResult();  
  15.      }  
  16.   
  17. }  
public class ItemDAOHibernate         extends     GenericHibernateDAO<Item, Long>         implements  ItemDAO {      public Bid getMaxBid(Long itemId) {         Query q = getSession().getNamedQuery(ItemDAO.QUERY_MAXBID);         q.setParameter("itemid", itemId);         return (Bid) q.uniqueResult();     }      public Bid getMinBid(Long itemId) {         Query q = getSession().getNamedQuery(ItemDAO.QUERY_MINBID);         q.setParameter("itemid", itemId);         return (Bid) q.uniqueResult();     }  }


下面是另外一个使用超类中具有不定参数的findByCriteria()方法的例子:

Java代码
  1. public class CategoryDAOHibernate  
  2.         extends      GenericHibernateDAO<Category, Long>  
  3.         implements   CategoryDAO {  
  4.   
  5.     public Collection<Category> findAll(boolean onlyRootCategories) {  
  6.         if (onlyRootCategories)  
  7.             return findByCriteria( Expression.isNull("parent") );  
  8.         else  
  9.             return findAll();  
  10.      }  
  11. }  
public class CategoryDAOHibernate         extends     GenericHibernateDAO<Category, Long>         implements  CategoryDAO {      public Collection<Category> findAll(boolean onlyRootCategories) {         if (onlyRootCategories)             return findByCriteria( Expression.isNull("parent") );         else             return findAll();     } }


为DAO准备工厂

原创粉丝点击