眾所周之。面向對象的基礎是抽象。也能夠說,抽象促使編程在不斷發展。
對於數據庫的訪問,以前寫過HqlHelper。EFHelper。編寫Spring+Hibernate框架下的應用。也相同離不了編寫一個通用的泛型GenericHibernateDao。查閱了網上不少的GenericHibernateDao實現,歸納整理為例如以下實現,供興許編碼參考。
一、 DAO泛型的接口 GenericDao
package ICT.framework.orm.hibernate; 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.DetachedCriteria; /** * * @author lianhai */ public interface GenericDao<T extends Serializable, PK extends Serializable> { // -------------------- 基本檢索、添加、改動、刪除操作 -------------------- // 依據主鍵獲取實體。假設沒有對應的實體。返回 null。
public T get(PK id); // 依據主鍵獲取實體並加鎖。假設沒有對應的實體。返回 null。 public T getWithLock(PK id, LockMode lock); // 依據主鍵獲取實體。
假設沒有對應的實體。拋出異常。 public T load(PK id); // 依據主鍵獲取實體並加鎖。假設沒有對應的實體,拋出異常。
public T loadWithLock(PK id, LockMode lock); // 獲取所有實體。 public List<T> loadAll(); // loadAllWithLock() ? // 更新實體 public void update(T entity); // 更新實體並加鎖 public void updateWithLock(T entity, LockMode lock); // 存儲實體到數據庫 public void save(T entity); // saveWithLock() // 添加或更新實體 public void saveOrUpdate(T entity); // 添加或更新集合中的所有實體 public void saveOrUpdateAll(Collection<T> entities); // 刪除指定的實體 public void delete(T entity); // 加鎖並刪除指定的實體 public void deleteWithLock(T entity, LockMode lock); // 依據主鍵刪除指定實體 public void deleteByKey(PK id); // 依據主鍵加鎖並刪除指定的實體 public void deleteByKeyWithLock(PK id, LockMode lock); // 刪除集合中的所有實體 public void deleteAll(Collection<T> entities); // -------------------- HQL ---------------------------------------------- // 使用HQL語句直接添加、更新、刪除實體 public int bulkUpdate(String queryString); // 使用帶參數的HQL語句添加、更新、刪除實體 public int bulkUpdate(String queryString, Object[] values); // 使用HQL語句檢索數據 public List find(String queryString); // 使用帶參數的HQL語句檢索數據 public List find(String queryString, Object[] values); // 使用帶命名的參數的HQL語句檢索數據 public List findByNamedParam(String queryString, String[] paramNames,Object[] values); // 使用命名的HQL語句檢索數據 public List findByNamedQuery(String queryName); // 使用帶參數的命名HQL語句檢索數據 public List findByNamedQuery(String queryName, Object[] values); // 使用帶命名參數的命名HQL語句檢索數據 public List findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values); // 使用HQL語句檢索數據,返回 Iterator public Iterator iterate(String queryString); // 使用帶參數HQL語句檢索數據,返回 Iterator public Iterator iterate(String queryString, Object[] values); // 關閉檢索返回的 Iterator public void closeIterator(Iterator it); // -------------------------------- Criteria ------------------------------ // 創建與會話無關的檢索標准對象 public DetachedCriteria createDetachedCriteria(); // 創建與會話綁定的檢索標准對象 public Criteria createCriteria(); // 使用指定的檢索標准檢索數據 public List findByCriteria(DetachedCriteria criteria); // 使用指定的檢索標准檢索數據。返回部分記錄 public List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults); // 使用指定的實體及屬性檢索(滿足除主鍵外屬性=實體值)數據 public List<T> findEqualByEntity(T entity, String[] propertyNames); // 使用指定的實體及屬性(非主鍵)檢索(滿足屬性 like 串實體值)數據 public List<T> findLikeByEntity(T entity, String[] propertyNames); // 使用指定的檢索標准檢索數據。返回指定范圍的記錄 public Integer getRowCount(DetachedCriteria criteria); // 使用指定的檢索標准檢索數據,返回指定統計值 public Object getStatValue(DetachedCriteria criteria, String propertyName, String StatName); // -------------------------------- Others -------------------------------- // 加鎖指定的實體 public void lock(T entity, LockMode lockMode); // 強制初始化指定的實體 public void initialize(Object proxy); // 強制馬上更新緩沖數據到數據庫(否則僅在事務提交時才更新) public void flush(); }
二、 GenericDao接口的實現類 GenericHibernateDao
package ICT.framework.orm.hibernate.impl; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.beanutils.PropertyUtils; import org.hibernate.Criteria; import org.hibernate.LockMode; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Example; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** * GenericHibernateDao 繼承 HibernateDao。簡單封裝 HibernateTemplate 各項功能, * 簡化基於Hibernate Dao 的編寫。* * @author lianhai */ @SuppressWarnings("unchecked") public class GenericHibernateDao<T extends Serializable, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> { // 實體類類型(由構造方法自己主動賦值) private Class<T> entityClass; // 構造方法,依據實例類自己主動獲取實體類類型 public GenericHibernateDao() { this.entityClass = null; Class c = getClass(); Type t = c.getGenericSuperclass(); if (t instanceof ParameterizedType) { Type[] p = ((ParameterizedType) t).getActualTypeArguments(); this.entityClass = (Class<T>) p[0]; } } // -------------------- 基本檢索、添加、改動、刪除操作 -------------------- // 依據主鍵獲取實體。
假設沒有對應的實體。返回 null。
public T get(PK id) { return (T) getHibernateTemplate().get(entityClass, id); } // 依據主鍵獲取實體並加鎖。
假設沒有對應的實體,返回 null。 public T getWithLock(PK id, LockMode lock) { T t = (T) getHibernateTemplate().get(entityClass, id, lock); if (t != null) { this.flush(); // 馬上刷新,否則鎖不會生效。 } return t; } // 依據主鍵獲取實體。
假設沒有對應的實體,拋出異常。
public T load(PK id) { return (T) getHibernateTemplate().load(entityClass, id); } // 依據主鍵獲取實體並加鎖。假設沒有對應的實體,拋出異常。 public T loadWithLock(PK id, LockMode lock) { T t = (T) getHibernateTemplate().load(entityClass, id, lock); if (t != null) { this.flush(); // 馬上刷新,否則鎖不會生效。 } return t; } // 獲取所有實體。
public List<T> loadAll() { return (List<T>) getHibernateTemplate().loadAll(entityClass); } // loadAllWithLock() ? // 更新實體 public void update(T entity) { getHibernateTemplate().update(entity); } // 更新實體並加鎖 public void updateWithLock(T entity, LockMode lock) { getHibernateTemplate().update(entity, lock); this.flush(); // 馬上刷新,否則鎖不會生效。 } // 存儲實體到數據庫 public void save(T entity) { getHibernateTemplate().save(entity); } // saveWithLock()? // 添加或更新實體 public void saveOrUpdate(T entity) { getHibernateTemplate().saveOrUpdate(entity); } // 添加或更新集合中的所有實體 public void saveOrUpdateAll(Collection<T> entities) { getHibernateTemplate().saveOrUpdateAll(entities); } // 刪除指定的實體 public void delete(T entity) { getHibernateTemplate().delete(entity); } // 加鎖並刪除指定的實體 public void deleteWithLock(T entity, LockMode lock) { getHibernateTemplate().delete(entity, lock); this.flush(); // 馬上刷新,否則鎖不會生效。
} // 依據主鍵刪除指定實體 public void deleteByKey(PK id) { this.delete(this.load(id)); } // 依據主鍵加鎖並刪除指定的實體 public void deleteByKeyWithLock(PK id, LockMode lock) { this.deleteWithLock(this.load(id), lock); } // 刪除集合中的所有實體 public void deleteAll(Collection<T> entities) { getHibernateTemplate().deleteAll(entities); } // -------------------- HQL ---------------------------------------------- // 使用HSQL語句直接添加、更新、刪除實體 public int bulkUpdate(String queryString) { return getHibernateTemplate().bulkUpdate(queryString); } // 使用帶參數的HQL語句添加、更新、刪除實體 public int bulkUpdate(String queryString, Object[] values) { return getHibernateTemplate().bulkUpdate(queryString, values); } // 使用HQL語句檢索數據 public List find(String queryString) { return getHibernateTemplate().find(queryString); } // 使用帶參數的HQL語句檢索數據 public List find(String queryString, Object[] values) { return getHibernateTemplate().find(queryString, values); } // 使用帶命名的參數的HQL語句檢索數據 public List findByNamedParam(String queryString, String[] paramNames, Object[] values) { return getHibernateTemplate().findByNamedParam(queryString, paramNames,values); } // 使用命名的HSQL語句檢索數據 public List findByNamedQuery(String queryName) { return getHibernateTemplate().findByNamedQuery(queryName); } // 使用帶參數的命名HQL語句檢索數據 public List findByNamedQuery(String queryName, Object[] values) { return getHibernateTemplate().findByNamedQuery(queryName, values); } // 使用帶命名參數的命名HQL語句檢索數據 public List findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values) { return getHibernateTemplate().findByNamedQueryAndNamedParam(queryName,paramNames, values); } // 使用HQL語句檢索數據,返回 Iterator public Iterator iterate(String queryString) { return getHibernateTemplate().iterate(queryString); } // 使用帶參數HQL語句檢索數據。返回 Iterator public Iterator iterate(String queryString, Object[] values) { return getHibernateTemplate().iterate(queryString, values); } // 關閉檢索返回的 Iterator public void closeIterator(Iterator it) { getHibernateTemplate().closeIterator(it); } // -------------------------------- Criteria ------------------------------ // 創建與會話無關的檢索標准 public DetachedCriteria createDetachedCriteria() { return DetachedCriteria.forClass(this.entityClass); } // 創建與會話綁定的檢索標准 public Criteria createCriteria() { return this.createDetachedCriteria().getExecutableCriteria( this.getSession()); } // 檢索滿足標准的數據 public List findByCriteria(DetachedCriteria criteria) { return getHibernateTemplate().findByCriteria(criteria); } // 檢索滿足標准的數據,返回指定范圍的記錄 public List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) { return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults); } // 使用指定的實體及屬性檢索(滿足除主鍵外屬性=實體值)數據 public List<T> findEqualByEntity(T entity, String[] propertyNames) { Criteria criteria = this.createCriteria(); Example exam = Example.create(entity); exam.excludeZeroes(); String[] defPropertys = getSessionFactory().getClassMetadata( entityClass).getPropertyNames(); for (String defProperty : defPropertys) { int ii = 0; for (ii = 0; ii < propertyNames.length; ++ii) { if (defProperty.equals(propertyNames[ii])) { criteria.addOrder(Order.asc(defProperty)); break; } } if (ii == propertyNames.length) { exam.excludeProperty(defProperty); } } criteria.add(exam); return (List<T>) criteria.list(); } // 使用指定的實體及屬性檢索(滿足屬性 like 串實體值)數據 public List<T> findLikeByEntity(T entity, String[] propertyNames) { Criteria criteria = this.createCriteria(); for (String property : propertyNames) { try { Object value = PropertyUtils.getProperty(entity, property); if (value instanceof String) { criteria.add(Restrictions.like(property, (String) value, MatchMode.ANYWHERE)); criteria.addOrder(Order.asc(property)); } else { criteria.add(Restrictions.eq(property, value)); criteria.addOrder(Order.asc(property)); } } catch (Exception ex) { // 忽略無效的檢索參考數據。
} } return (List<T>) criteria.list(); } // 使用指定的檢索標准獲取滿足標准的記錄數 public Integer getRowCount(DetachedCriteria criteria) { criteria.setProjection(Projections.rowCount()); List list = this.findByCriteria(criteria, 0, 1); return (Integer) list.get(0); } // 使用指定的檢索標准檢索數據,返回指定統計值(max,min,avg,sum) public Object getStatValue(DetachedCriteria criteria, String propertyName, String StatName) { 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); } // -------------------------------- Others -------------------------------- // 加鎖指定的實體 public void lock(T entity, LockMode lock) { getHibernateTemplate().lock(entity, lock); } // 強制初始化指定的實體 public void initialize(Object proxy) { getHibernateTemplate().initialize(proxy); } // 強制馬上更新緩沖數據到數據庫(否則僅在事務提交時才更新) public void flush() { getHibernateTemplate().flush(); } }
以上就實現了泛型的 Hibernate Dao 了,以下的樣例就是業務對象對 GenericHibernateDao的使用
三、 業務對象 Article
public class Article implements Serializable { private static final long serialVersionUID = 1072812006693587010L; private long id; private String title; private String author; private Date pubDate; private String content; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
定義 Article 業務對象的Dao 接口 IArticleDao ,它繼承自 GenericDao 接口,以獲得當中的方法。
能夠在 IArticleDao 中加入 Article 業務對象特有的方法,也能夠直接使用 GenericDao 中提供的全部方法IArticleDao接口指定業務對象的類型和主鍵的類型 <Article,Long>
public interface IArticleDAO extends GenericDao <Article,Long> { // public void findById(Long id); }
五、 ArticleHibernateDao 類
如今就能夠定義 ArticleHibernateDao 類了,它僅僅要實現 IArticleDao 接口並繼承 GenericHibernateDao 類 就能夠使用全部的 Generic 接口和 IArticleDao 接口中的定義的方法。假設你在 IArticleDao 接口里指定了Article業務對象特有的方法,就在ArticleHibernateDao實現這些方法。而Generic 接口中的方法。在ArticleHibernateDao 的父類 GenericHibernateDao 中已經所有實現了,直接調用就能夠方便的訪問數據庫。
public class ArticleHibernateDao extends GenericHibernateDao<Article,Long> implements IArticleDAO { }
故:
其它的業務對象也能夠參照 Article 和 ArticleHibernateDao 類來定義 , GenericDao 接口中有的通用方法就直接調用,不足的以后補充。其它業務對象特有的方法就 在其它業務對象的 Dao接口(繼承GenericDao接口) 中定義並通過 GenericHibernateDao 子類來實現。 節省非常多反復代碼。簡單幾步就能夠使用GenericDao接口的實現類 GenericHibernateDao 方便地訪問數據庫。
補:
最后提供一個 Article 業務對象的 Hibernate 映射文件和一個 ArticleHibernateDao 類的測試類。
Article的映射文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Article.hbm.xml --> <hibernate-mapping> <class name="com.pplsunny.model.Article" table="article"> <id name="id" type="java.lang.Long"> <column name="id" /> <generator class="native" /> </id> <property name="title" type="java.lang.String"> <column name="title" length="100" /> </property> <property name="author"> <column name="author" length="32" /> </property> <property name="pubDate" type="java.util.Date"> <column name="pubDate" /> </property> <property name="content" type="java.lang.String"> <column name="content" /> </property> </class> </hibernate-mapping>
ArticleHibernateDao的測試類,僅僅提供了seve(article) 方法的測試代碼
public class ArticleHibernateDaoTest extends TestCase { ApplicationContext ctx = new ClassPathXmlApplicationContext( "applicationContext.xml"); ArticleHibernateDao adh = (ArticleHibernateDao) ctx .getBean("articleHibernateDao"); public void testSave() { Article art = (Article) ctx.getBean("article"); art.setId(1); art.setTitle("標題1"); art.setAuthor("作者1"); adh.save(art); } }