泛型是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];
}
}