天天看點

基于hibernate的泛型Dao層設計

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

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

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

通用DAO接口:

package com.baiyyy.util.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實作:

package com.baiyyy.util.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, 0, 1);

    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, 0, 1);

    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];​

​​

​  }​

​​

​}​