泛型是JDK1.5的一個新的特性,使用泛型機制編寫的程序代碼要比那些雜亂的使用Object變量,然后再進行強制類型轉換的代碼具有更好的安全性和可讀性。如果你的系統運行在JDK1.5以上的版本上,建議多使用泛型來代替無休止的對象轉換。

         在軟件設計中我們開始對系統進行三層甚至是多層架構了,目的是職責更加的明確,功能更加的分離。而常常使用的三層架構就是將表現層、業務邏輯層和持久層進行分離,每一層關注點不同,職能更加的清晰。所以DAO的設計模式現在已經被我們所接受,下面就介紹一下泛型DAO的設計和實現。

         這次的DAO例子是基于接口的.很多工具, 像Hibernate已經提供了數據庫的便攜訪問,所以我們不是為持久層的輕便而設計接口. 然而, DAO接口在較為復雜的應用中更有意義, 當有幾個持久化服務被封裝到一個持久層的時候, 我想在很多情況下你應該直接使用Hibernate或者JPA, 而使用外加的DAO層最好的理由是為了實現更高的抽象化(例如:定義方法名findAll(String hql)而不是無數次地重復session.createQuery(...))


通用DAO接口:
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;

/**
 * 承有業務數據的基礎訪問接口
 * <p>
 * 承有CRUD (創建,讀取,修改和刪陿)基本數據的操作在這個接口中都是獨立的_ 并且承有的DAO都可以使用這些基本實玿
 * 
 * 
@author yongtree
 * 
 * @date:2008-03-04
 
*/

public interface IBaseDAO<T, ID extends Serializable> {

  
/***************************************************************************
   * -------------------基本棿索?增加?修改?刪除操使---------------------------- *
   *************************************************************************
*/


  
// --------findById()方法是?過get(ID id)得到實體對象-----------------------
  /**
   * 通過ID來得到實體對豿
   * 
   * 
@param id
   *            實體對象的標識符
   * 
@param lock
   *            使用的鎖模式
   * 
@return 該主鍵忼對應的實體對象
   
*/

  
public T findById(ID id, LockMode lock);

  
/**
   * 通過ID來得到實體對豿
   * 
   * 
@param id
   * 
@return T
   
*/

  
public T findById(ID id);

  
/**
   * 通過ID來得到實體對豿(為兼容其他開發成員的原有程序,保留使甿)
   * 
   * 
@param c
   * 
@param id
   * 
@return T
   
*/

  
public T findById(Class c, ID id);

  
// -------------loadById()是調用hibernate的load方法------------

  
public T loadById(ID id);

  
/**
   * 通過id load對象
   * 
   * 
@param id
   * 
@param lock
   * 
@return
   
*/

  
public T loadById(ID id, LockMode lock);

  
/**
   * 獲取全部的實使
   * 
   * 
@return
   
*/

  
public List<T> loadAll();

  
/**
   * 保存丿個實體對豿
   * 
   * 
@param entity
   
*/

  
public T saveEntity(T entity);

  
/**
   * 更新丿個實體對豿
   * 
   * 
@param entity
   
*/

  
public void updateEntity(T entity);

  
public void updateEntity(T entity, LockMode lock);

  
/**
   * 增加或更新集合中的全部實使
   * 
   * 
@param entities
   
*/

  
public void saveOrUpdateAll(Collection<T> entities);

  
/**
   * 刪除丿個實使
   * 
   * 
@param entity
   * 
@throws Exception
   
*/

  
public void deleteEntity(T entity);

  
public void deleteEntity(T entity, LockMode lock);

  
/**
   * 根據主鍵刪除指定實體
   * 
   * 
@param id
   
*/

  
public void deleteEntityById(ID id);

  
public void deleteEntityById(ID id, LockMode lock);

  
/**
   * 批量刪除
   * 
   * 
@param entities
   
*/

  
public void deleteAll(Collection<T> entities);

  
/**
   * 通過合并的方式更新對豿
   * 
   * 
@param entity
   *            void
   
*/

  
public void merge(T entity);

  
/***************************************************************************
   * ------------------------------使用HQL語句-------------------------------- *
   *************************************************************************
*/


  
/**
   * 使用HQL語句進行對象的查諉
   * 
   * 
@param hsql
   *            查詢語句
   * 
@return 符合條件的對豿
   
*/


  
public T getEntity(String hsql);

  
/**
   * 使用HQL語句進行查詢
   * 
   * 
@param hsql
   *            查詢語句
   * 
@return 符合條件的對象集吿
   
*/

  
public List<T> getEntities(String hsql);

  
/**
   * 使用帶參數的HQL語句進行查詢
   * 
   * 
@param hsql
   * 
@param obj
   * 
@return
   
*/

  
public List<T> getEntities(String hsql, Object[] values);

  
public List<T> getEntities(String hql, int start, int number);

  
public List<T> getEntities(String hql, int start, int number,
      Object[] values);

  
/**
   * 使用命名的HQL語句棿索數捿
   * 
   * 
@param queryName
   * 
@return
   
*/

  
public List<T> findByNamedQuery(String queryName);

  
/**
   * 使用帶參數的命名HSQL語句棿索數捿
   * 
   * 
@param queryName
   * 
@param values
   * 
@return
   
*/

  
public List<T> findByNamedQuery(String queryName, Object[] values);

  
/**
   * 使用帶命名參數的命名HSQL語句棿索數捿
   * 
   * 
@param queryName
   * 
@param paramNames
   * 
@param values
   * 
@return
   
*/

  
public List<T> findByNamedQuery(String queryName, String[] paramNames,
      Object[] values);

  
/**
   * 使用HQL語句棿索數據,返回 Iterator
   * 
   * 
@param queryString
   * 
@return
   
*/

  
public Iterator<T> iterate(String queryString);

  
/**
   * 使用帶參數HSQL語句棿索數據,返回 Iterator
   * 
   * 
@param queryString
   * 
@param values
   * 
@return
   
*/

  
public Iterator<T> iterate(String queryString, Object[] values);

  
/***************************************************************************
   * -----------------------------Criteria動濁查諉---------------------------- *
   *************************************************************************
*/


  
/**
   * 創建與會話無關的棿索標準對豿
   
*/

  
public DetachedCriteria createDetachedCriteria();

  
/**
   * 創建與會話綁定的棿索標準對豿
   * 
   * 
@return
   
*/

  
public Criteria createCriteria();

  
/**
   * 使用指定的檢索標準檢索數捿
   * 
   * 
@param criteria
   * 
@return
   
*/

  
public List<T> findByCriteria(DetachedCriteria criteria);

  
/**
   * 使用指定的檢索標準檢索數據,返回部分記錄
   * 
   * 
@param criteria
   * 
@param firstResult
   * 
@param maxResults
   * 
@return
   
*/

  
public List<T> findByCriteria(DetachedCriteria criteria, int firstResult,
      
int maxResults);

  
/**
   * 通過動濁查詢條件進行查諉
   * 
   * 
@param criterion
   * 
@return List<T>
   
*/

  @SuppressWarnings(
"unchecked")
  
public List<T> findByCriteria(Criterion criterion);

  
/**
   * 使用指定的檢索標準檢索數據,返回指定范圍的記彿
   * 
   * 
@param criteria
   * 
@return
   
*/

  
public Integer getRowCount(DetachedCriteria criteria);

  
/**
   * 使用指定的檢索標準檢索數據,返回指定統計倿
   * 
   * 
@param criteria
   * 
@param propertyName
   * 
@param StatName
   *            (max,min,avg,sum)
   * 
@return
   
*/

  
public Object getStatValue(DetachedCriteria criteria, String propertyName,
      String StatName);

  
/**
   * 通過給定的一個對象,查找與其匹配的對象,表關聯比較多時,用戶可以自己根據霿要擴展?
   * 
   * 
@param entity
   * 
@return List<T>
   
*/

  
public List<T> findByExample(T entity);

  
/***************************************************************************
   * -------------------------Others ----------------------------------------*
   *************************************************************************
*/


  
/**
   * 加鎖指定的實使
   * 
   * 
@param entity
   * 
@param lockMode
   
*/

  
public void lock(T entity, LockMode lockMode);

  
/**
   * 強制立即更新緩沖數據到數據庫(否則僅在事務提交時才更新)
   
*/

  
public void flush();

  
/**
   * 清空緩存
   * 
   * void
   
*/

  
public void clear();

  
/***************************************************************************
   * --------------------------------相關知識炿--------------------------------*
   * 
   * 1、Session的load方法和get方法都是通過給定的ID從數據庫中加載一個持久化的對象?但兩個斿*
   * 法的區別在于:當數據庫不存在于ID對應的記錄時,load()方法拋出異常,迌get()方法返回null*
   **************************************************************************
*/


}
 

設計完接口,我們就要實現我們創建的接口,我們如果使用Hibernate,那么就做一個hibernate的實現,如果使用JPA,那么就做一個JPA實現。以下采用hibernate進行實現。

通用Hibernate DAO實現:



/**
 * @filename:BaseHibernateDAO.java
 
*/


import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;

import com.baiyyy.workflow.pojo.TWfPackage;

/**
 * 用Hibernate實現通用DAO接口
 * 
 * 
@author yongtree
 * @date 2008-3-10
 * 
@param <T>
 * 
@param <ID>
 
*/

public class BaseHibernateDAO<T, ID extends Serializable> implements
    IBaseDAO
<T, ID> {
  
// 保持實體對象類的類型
  private Class<T> persistentClass;

  
private Session session;

  
/**
   * 構?方泿
   
*/

  @SuppressWarnings(
"unchecked")
  
public BaseHibernateDAO() {
    
//下面這種方式丿直有錯誤,不能得到真正的T.class,迌是Object.class
    
// this.persistentClass=GenericsUtils.getSuperClassGenricType(getClass());
    
// System.out.println(obj.getClass().getName());
  }


  @SuppressWarnings(
"unchecked")
  
public BaseHibernateDAO(Class clazz) {
    
this.persistentClass = clazz;
  }


  
/**
   * 
@param session
   *            the session to set
   
*/

  
public void setSession(Session session) {
    
this.session = session;
  }


  
/**
   * 得到當前線程的Session對象的實便
   * 
   * 
@return
   
*/

  
protected Session getSession() {
    System.out.println(
"get session");
    
return HibernateUtil.getCurrentSession();
  }


  
/**
   * 得到持久化對象的類型
   * 
   * 
@return 持久化類的類垿
   
*/

  
protected Class<T> getPersistentClass() {
    
return persistentClass;
  }


  @SuppressWarnings(
"unchecked")
  
public T findById(ID id, LockMode lock) {
    
// TODO Auto-generated method stub
    T entity = (T) getSession().get(getPersistentClass(), id, lock);
    
if (entity != null{
      
this.flush();
    }


    
return entity;
  }


  @SuppressWarnings(
"unchecked")
  
public T findById(Class c, ID id) {
    
// TODO Auto-generated method stub
    T entity;

    entity 
= (T) getSession().get(c, id);

    
return entity;
  }


  @SuppressWarnings(
"unchecked")
  
public T findById(ID id) {
    
// TODO Auto-generated method stub
    T entity = (T) getSession().get(getPersistentClass(), id);

    
return entity;
  }


  @SuppressWarnings(
"unchecked")
  
public T loadById(ID id) {
    
// TODO Auto-generated method stub
    T entity = (T) getSession().load(getPersistentClass(), id);
    
return entity;
  }


  @SuppressWarnings(
"unchecked")
  
public T loadById(Class c, ID id) {
    
// TODO Auto-generated method stub
    T entity = (T) getSession().load(c, id);
    
return entity;
  }


  @SuppressWarnings(
"unchecked")
  
public T loadById(ID id, LockMode lock) {
    
// TODO Auto-generated method stub
    T entity = (T) getSession().load(getPersistentClass(), id, lock);
    
return entity;
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> loadAll() {
    List
<T> list = getSession().createQuery(
        
"from " + getPersistentClass().getName()).list();
    
return list;
  }


  
public T saveEntity(T entity) {
    
// TODO Auto-generated method stub

    getSession().save(entity);
    
this.flush();
    
return entity;
  }


  
public void updateEntity(T entity) {
    
// TODO Auto-generated method stub
    getSession().saveOrUpdate(entity);
    
this.flush();
  }


  
/**
   * 該實現類暫時沒有實現更新加鎖的操使
   
*/

  
public void updateEntity(T entity, LockMode lock) {
    
// TODO Auto-generated method stub
    getSession().saveOrUpdate(entity);
    
this.flush();
  }


  
public void saveOrUpdateAll(Collection<T> entities) {
    getSession().saveOrUpdate(entities);
    
this.flush();
  }


  
public void deleteEntity(T entity) {
    
// TODO Auto-generated method stub
    getSession().delete(entity);
    
this.flush();
  }


  
/**
   * 該實現沒有實現加鎖刪除對象的操作,在spring的DAO實現中已經實玿
   
*/

  
public void deleteEntity(T entity, LockMode lock) {
    
// TODO Auto-generated method stub
    getSession().delete(entity);
    
this.flush();
  }


  
public void deleteEntityById(ID id) {
    
this.deleteEntity(this.loadById(id));
    
this.flush();
  }


  
// 該實現沒有實現加鎖的刪除,在spring的dao中已經實現了
  public void deleteEntityById(ID id, LockMode lock) {
    
this.deleteEntity(this.loadById(id));
    
this.flush();
  }


  
public void deleteAll(Collection<T> entities) {
    
this.flush();
    getSession().delete(entities);
  }

  
  
public void merge(T entity){
    getSession().merge(entity);
    
this.flush();
  }


  @SuppressWarnings(
"unchecked")
  
public T getEntity(String hsql) {
    T uniqueResult 
= (T) getSession().createQuery(hsql).uniqueResult();
    
// TODO Auto-generated method stub
    return uniqueResult;
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> getEntities(String hsql) {
    
// TODO Auto-generated method stub

    List list 
= getSession().createQuery(hsql).list();
    
return list;
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> getEntities(String hql, int start, int number,
      Object[] values) 
{
    
// TODO Auto-generated method stub
    Query query = getSession().createQuery(hql);
    
for (int i = 0; i < values.length; i++{
      query.setParameter(i, values[i]);
    }

    query.setFirstResult(start);
    query.setMaxResults(number);
    List list 
= query.list();
    
return list;
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> getEntities(String hql, int start, int number) {
    
// TODO Auto-generated method stub
    Query query = getSession().createQuery(hql);
    query.setFirstResult(start);
    query.setMaxResults(number);
    List list 
= query.list();
    
return list;
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> getEntities(String hql, Object[] values) {
    
// TODO Auto-generated method stub
    Query query = getSession().createQuery(hql);
    
for (int i = 0; i < values.length; i++{
      query.setParameter(i, values[i]);
    }

    
return query.list();
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> findByNamedQuery(String queryName) {
    
// TODO Auto-generated method stub
    return getSession().getNamedQuery(queryName).list();
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> findByNamedQuery(String queryName, Object[] values) {
    
// TODO Auto-generated method stub
    Query query = getSession().getNamedQuery(queryName);
    
for (int i = 0; i < values.length; i++{
      query.setParameter(i, values);
    }

    
return query.list();
  }


  
/**
   * 注意:該方法是?過設置參數來進行命名查詢,承以在傳參數時,一定要注意paramNames和values的長度,位置要一丿對應?
   
*/

  @SuppressWarnings(
"unchecked")
  
public List<T> findByNamedQuery(String queryName, String[] paramNames,
      Object[] values) 
{
    
// TODO Auto-generated method stub
    Query query = getSession().getNamedQuery(queryName);
    
for (int i = 0; i < paramNames.length; i++{
      query.setParameter(paramNames[i], values[i]);
    }

    
return query.list();
  }


  @SuppressWarnings(
"unchecked")
  
public Iterator<T> iterate(String hql) {
    
// TODO Auto-generated method stub
    return getSession().createQuery(hql).iterate();
  }


  @SuppressWarnings(
"unchecked")
  
public Iterator<T> iterate(String hql, Object[] values) {
    
// TODO Auto-generated method stub
    Query query = getSession().createQuery(hql);
    
for (int i = 0; i < values.length; i++{
      query.setParameter(i, values[i]);
    }

    
return query.iterate();
  }


  
public DetachedCriteria createDetachedCriteria() {
    
// TODO Auto-generated method stub
    return DetachedCriteria.forClass(this.persistentClass);
  }


  
public Criteria createCriteria() {
    
// TODO Auto-generated method stub
    return this.createDetachedCriteria().getExecutableCriteria(
        
this.getSession());
  }


  
/**
   * 該方法沒有經過驗證,不能保證正確,在spring的實現中已經實現億
   
*/

  @SuppressWarnings(
"unchecked")
  
public List<T> findByCriteria(DetachedCriteria criteria) {
    
// TODO Auto-generated method stub
    return criteria.getExecutableCriteria(this.getSession()).list();
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> findByCriteria(DetachedCriteria criteria, int firstResult,
      
int maxResults) {
    
// TODO Auto-generated method stub
    return criteria.getExecutableCriteria(this.getSession())
        .setFirstResult(firstResult).setMaxResults(maxResults).list();

  }


  
/**
   * 動濁查諉
   * 
   * 
@param criterion
   * 
@return
   
*/

  
public @SuppressWarnings("unchecked")
  List
<T> findByCriteria(Criterion criterion) {
    Criteria crit 
= getSession().createCriteria(getPersistentClass());
    
for (Criterion c : criterion) {

      
if (c != null{

        crit.add(c);

      }

    }

    List list 
= crit.list();
    
return list;
  }


  @SuppressWarnings(
"unchecked")
  
public Integer getRowCount(DetachedCriteria criteria) {
    
// TODO Auto-generated method stub
    criteria.setProjection(Projections.rowCount());
    List list 
= this.findByCriteria(criteria, 01);
    
return (Integer) list.get(0);

  }


  @SuppressWarnings(
"unchecked")
  
public Object getStatValue(DetachedCriteria criteria, String propertyName,
      String StatName) 
{
    
// TODO Auto-generated method stub
    if (StatName.toLowerCase().equals("max"))
      criteria.setProjection(Projections.max(propertyName));
    
else if (StatName.toLowerCase().equals("min"))
      criteria.setProjection(Projections.min(propertyName));
    
else if (StatName.toLowerCase().equals("avg"))
      criteria.setProjection(Projections.avg(propertyName));
    
else if (StatName.toLowerCase().equals("sum"))
      criteria.setProjection(Projections.sum(propertyName));
    
else
      
return null;
    List list 
= this.findByCriteria(criteria, 01);
    
return list.get(0);
  }


  @SuppressWarnings(
"unchecked")
  
public List<T> findByExample(T exampleInstance) {
    
// TODO Auto-generated method stub
    Criteria crit = getSession().createCriteria(getPersistentClass());
    Example example 
= Example.create(exampleInstance);
    example.ignoreCase().enableLike(MatchMode.ANYWHERE);
// 忽略大小寫,并進行模糊比辿
    example.excludeZeroes();// 對于屬濧中有數字類型的,如果exampleInstance的屬性忼為0,就把它添加到查詢中
    crit.add(example);
    
return crit.list();

  }


  
public void lock(T entity, LockMode lockMode) {
    
// TODO Auto-generated method stub
    getSession().lock(entity, lockMode);
  }


  
public void flush() {
    
// TODO Auto-generated method stub
    getSession().flush();
  }


  
public void clear() {
    
// TODO Auto-generated method stub
    getSession().clear();
  }


}
 

到現在為止,Hibernate通用DAO已經建立完成,作為一個通用的工具類,我們希望每個實體DAO都能繼承這個DAO。繼續發揚接口編程,每一個持久化實體類我們都建立一個接口,并且讓這些接口都繼承IBaseDAO。

ParticipantDAO的寫法:

public interface ParticipantDAO extends IBaseDAO<TWfParticipants, Integer>{
  //自定義該實體的接口
}

ParticipantDAO實現類的寫法:

public class ParticipantDAOImpl extends
    BaseHibernateDAO<TWfParticipants, Integer> implements
    ParticipantDAO {

  public ParticipantDAOImpl() {
    super(TWfParticipants.class);
  }
   //實現自定義的方法
}

注:在BaseHibernateDAO的無參數構造函數中

 public BaseHibernateDAO() {
    //下面這種方式一直有錯誤,不能得到真正的T.class,迌是Object.class
    // this.persistentClass=GenericsUtils.getSuperClassGenricType(getClass());
  }
這種方式的寫法在springside中使用過,但是自己調試始終有錯誤,始終無法得到T.class,得到的只是Oject.class,不知道怎么解決,還請高人指點。

以下是我的替代方法,可能不是太好。構建一個帶有Class參數的構造函數,讓每個DAO硬性傳入class。

public BaseHibernateDAO(Class clazz) {
    this.persistentClass = clazz;
  }
然后在子類DAO的構造參數中向父類傳遞一個class,因為一個DAO對應著一個實體,所以傳入一個實體的class也是沒有什么不可以的。

 public ParticipantDAOImpl() {
    super(TWfParticipants.class);
  }
補充GenericsUtils.java:

public class GenericsUtils {
  private static final Log log = LogFactory.getLog(GenericsUtils.class);

  private GenericsUtils() {
  }

  /**
   * 通過反射,獲得定義Class時聲明的父類的范型參數的類型. 如public BookManager extends GenricManager<Book>
   *
   * @param clazz
   *            The class to introspect
   * @return the first generic declaration, or <code>Object.class</code> if
   *         cannot be determined
   */
  public static Class getSuperClassGenricType(Class clazz) {
    return getSuperClassGenricType(clazz, 0);
  }

  /**
   * 通過反射,獲得定義Class時聲明的父類的范型參數的類型. 如public BookManager extends GenricManager<Book>
   *
   * @param clazz
   *            clazz The class to introspect
   * @param index
   *            the Index of the generic ddeclaration,start from 0.
   */
  public static Class getSuperClassGenricType(Class clazz, int index)
      throws IndexOutOfBoundsException {

    Type genType = clazz.getGenericSuperclass();
//    Type genType = clazz;

    if (!(genType instanceof ParameterizedType)) {
      log.warn(clazz.getSimpleName()
          + "'s superclass not ParameterizedType");
      return clazz;
    }

    Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

    if (index >= params.length || index < 0) {
      log.warn("Index: " + index + ", Size of " + clazz.getSimpleName()
          + "'s Parameterized Type: " + params.length);
      return Object.class;
    }
    if (!(params[index] instanceof Class)) {
      log
          .warn(clazz.getSimpleName()
              + " not set the actual class on superclass generic parameter");
      return Object.class;
    }
    return (Class) params[index];
  }
}

在實際的項目中,我們常常忽略了業務邏輯層,我們有人喜歡將大部分的邏輯放在表現層的Java Bean中,也有人喜歡在DAO中編寫自己的業務邏輯,雖然功能都能實現,但是職責不明,讓我們面對這些雜亂無章的代碼,我們無所適從。泛型DAO的設計我感覺很大程度上可以強制程序員不要在DAO中書寫自己的邏輯代碼,也讓我們慢慢的建立自己業務邏輯層(在EJB,spring這樣的框架沒有引入的情況下)。