编写Spring+Hibernate框架下的应用,总是离不了编写一个通用的泛型GenericHibernateDao。查阅了网上不少的GenericHibernateDao实现,归纳整理为如下实现,供后续编码参考。
首先定义接口泛型DAO接口 GenericDao
package
com.th.huz;
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
lny
*/
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);
//
-------------------- HSQL ----------------------------------------------
//
使用HSQL语句直接增加、更新、删除实体
public
int
bulkUpdate(String queryString);
//
使用带参数的HSQL语句增加、更新、删除实体
public
int
bulkUpdate(String queryString, Object[] values);
//
使用HSQL语句检索数据
public
List find(String queryString);
//
使用带参数的HSQL语句检索数据
public
List find(String queryString, Object[] values);
//
使用带命名的参数的HSQL语句检索数据
public
List findByNamedParam(String queryString, String[] paramNames,
Object[] values);
//
使用命名的HSQL语句检索数据
public
List findByNamedQuery(String queryName);
//
使用带参数的命名HSQL语句检索数据
public
List findByNamedQuery(String queryName, Object[] values);
//
使用带命名参数的命名HSQL语句检索数据
public
List findByNamedQueryAndNamedParam(String queryName,
String[] paramNames, Object[] values);
//
使用HSQL语句检索数据,返回 Iterator
public
Iterator iterate(String queryString);
//
使用带参数HSQL语句检索数据,返回 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接口的Hibernate的实现类 GenericHibernateDao
package
com.th.huz;
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
lny
*/
@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);
}
//
-------------------- HSQL ----------------------------------------------
//
使用HSQL语句直接增加、更新、删除实体
public
int
bulkUpdate(String queryString) {
return
getHibernateTemplate().bulkUpdate(queryString);
}
//
使用带参数的HSQL语句增加、更新、删除实体
public
int
bulkUpdate(String queryString, Object[] values) {
return
getHibernateTemplate().bulkUpdate(queryString, values);
}
//
使用HSQL语句检索数据
public
List find(String queryString) {
return
getHibernateTemplate().find(queryString);
}
//
使用带参数的HSQL语句检索数据
public
List find(String queryString, Object[] values) {
return
getHibernateTemplate().find(queryString, values);
}
//
使用带命名的参数的HSQL语句检索数据
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);
}
//
使用带参数的命名HSQL语句检索数据
public
List findByNamedQuery(String queryName, Object[] values) {
return
getHibernateTemplate().findByNamedQuery(queryName, values);
}
//
使用带命名参数的命名HSQL语句检索数据
public
List findByNamedQueryAndNamedParam(String queryName,
String[] paramNames, Object[] values) {
return
getHibernateTemplate().findByNamedQueryAndNamedParam(queryName,
paramNames, values);
}
//
使用HSQL语句检索数据,返回 Iterator
public
Iterator iterate(String queryString) {
return
getHibernateTemplate().iterate(queryString);
}
//
使用带参数HSQL语句检索数据,返回 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 对应文章表的 aticle 表
package
com.th.huz.model;
import
java.io.Serializable;
import
java.util.Date;
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>
package
com.th.huz.model;
import
com.th.huz.dao.GenericDao;
import
com.th.huz.model.Article;
public
interface
IArticleDAO
extends
GenericDao
<
Article,Long
>
{
//
public void findById(Long id);
}
然后就可以定义 ArticleHibernateDao 类了,它只要实现 IArticleDao 接口并继承 GenericHibernateDao 类 就可以使用所有的 Generic 接口和 IArticleDao 接口中的定义的方法。如果你在 IArticleDao 接口里指定了Article业务对象特有的方法,就在ArticleHibernateDao实现这些方法。而Generic 接口中的方法,在ArticleHibernateDao 的父类 GenericHibernateDao 中已经全部实现了,直接调用就可以方便的访问数据库。
package
com.th.huz.model;
import
com.th.huz.dao.GenericHibernateDao;
public
class
ArticleHibernateDao
extends
GenericHibernateDao
<
Article,Long
>
implements
IArticleDAO {
}
其他的业务对象也可以参照 Article 和 ArticleHibernateDao 类来定义 , GenericDao 接口中有的通用方法就直接调用,不足的以后补充,其他业务对象特有的方法就 在其他业务对象的 Dao接口(继承GenericDao接口) 中定义并通过 GenericHibernateDao 子类来实现。 节省很多重复代码,简单几步就可以使用GenericDao接口的实现类 GenericHibernateDao 方便地访问数据库。
最后提供一个 Article 业务对象的 Hibernate 映射文件 和 建表SQL脚本 和 一个 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"
>
<
hibernate-mapping
>
<
class
name
="com.th.huz.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
>
Article对应的article表的建表脚本
if
exists
(
select
*
from
dbo.sysobjects
where
id
=
object_id
(N
'
[dbo].[article]
'
)
and
OBJECTPROPERTY
(id, N
'
IsUserTable
'
)
=
1
)
drop
table
[
dbo
]
.
[
article
]
GO
CREATE
TABLE
[
dbo
]
.
[
article
]
(
[
id
]
[
int
]
IDENTITY
(
1
,
1
)
NOT
NULL
,
[
title
]
[
varchar
]
(
100
) COLLATE Chinese_PRC_CI_AS
NOT
NULL
,
[
author
]
[
varchar
]
(
32
) COLLATE Chinese_PRC_CI_AS
NULL
,
[
pubDate
]
[
datetime
]
NULL
,
[
content
]
[
text
]
COLLATE Chinese_PRC_CI_AS
NULL
)
ON
[
PRIMARY
]
TEXTIMAGE_ON
[
PRIMARY
]
GO
ArticleHibernateDao的测试类,只提供了seve(article) 方法的测试代码
package
com.th.huz.test;
import
junit.framework.TestCase;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import
com.th.huz.model.Article;
import
com.th.huz.model.ArticleHibernateDao;
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);
}
}
以上代码在集成了 Hibernate 的 Spring 框架下调试通过,仅供学习参考,请自行搭配你的环境来调试,本人也是自己初学,有没说清楚的地方敬请指教。