Hibernate, Java 5 and DAO

在进行Hibernate开发过程中,我们通常会使用DAO模式,有一些通用的数据操作方法,如CRUD,我们通常会将这些方法集中在一个DAO,这样会简便很多。如在AppFuse中,创建了一个DAO接口,包含一些常用的方法,接口如下:


public interface DAO {
public List getObjects(Class clazz);
public Object getObject(Class clazz, Serializable id);
public void saveObject(Object o);
public void removeObject(Class clazz, Serializable id);
}

这里的代码包含了许多entity类型的信息,也就是DAO接口中的Class clazz。接下来AppFuse同样创建一个缺省的实现类:BaseDAOHibernate,将这个接口做一缺省实现。以后我们创建的新的DAO需要继承DAO接口,如UserDAO,RoleDAO都继承DAO接口,对应的DAO实现都继承BaseDAOHibernate,再实现指定的接口,如UserDAOHibernate继承BaseDAOHibernate,实现UserDAO接口。

如果你的项目在使用Java 5,那么再这么做可能有点不适合,在调用AppFuse的DAO接口时,你通常还需要进行额外的操作:造型(cast type),提供entity类名,List数据没有包含元素类型信息等,这里要感谢Java 5的Generics,让我们做同样的事情轻松多了,下面让我们看看在Java 5下如何规划DAO接口。首先我们创建同样的一个DAO接口,代码如下:


public interface AbstractDao{
public Serializable create(T po);
public T getById(Serializable id);
public void update(T po);
public void delete(T po);
public List findAll();
public List findByCriterion(Criterion... criterion);
}

在这个接口中,我们提供了基本的CRUD和简单的查询(使用了Hibernate的Criterion),同时我们引入Generics机制,enity的类型我们用T代替,在后面就可以看到这样做的带来的好处,同时我们创建一个这个接口的缺省实现:bstractHibernateDao,代码如下:


public abstract class AbstractHibernateDao extends ibernateDaoSupport
implements AbstractDao
{
private Class poClass;
public AbstractHibernateDao(Class poClass)
{
this.poClass = poClass;
}
public T getById(Serializable id)
{
return (T) getHibernateTemplate().get(poClass, id);
}
public void delete(T po)
{
getHibernateTemplate().delete(po);
}
public List findAll()
{
return getHibernateTemplate().find("from " + poClass.getName() + " obj");
}
public List findByCriterion(final Criterion... criterion)
{
return getHibernateTemplate().executeFind(new HibernateCallback()
{
public Object doInHibernate(Session session) throws HibernateException, SQLException
{
Criteria criteria=session.createCriteria(poClass);
for (Criterion c : criterion)
{
criteria.add(c);
}
return criteria.list();
}
});
}
public Serializable create(T po)
{
return getHibernateTemplate().save(po);
}
public void update(T po)
{
getHibernateTemplate().update(po);
}
}

在这个实现中,我们需要提供Entity的类型信息,也就是代码中的PoClass,AbstractHibernateDao只包含一个构造函数,那么所有继承该类的子类必须调用AbstractHibernateDao类的构造函数,保证了entity的类型被准确赋值。

下面让我们看看如何创建业务的DAO,我们只需创建一个新的DAO,继承AbstractDao即可,这里要提供entity的类型信息,如PersonPO,代码如下:


public interface UserDao extends AbstractDao
{
public static final String BEANNAME = "UserDao";
public PersonPO findUserByNameAndPassword(String name,String password);
}

基本的CRUD完全没有了,我们只需关注其他的一些业务方面,在这个接口中只需继承AbstractDao,其中PersernPO为entity的类型,这个是Generics需要的。下面我们看一下UserDao的接口实现,代码很简单,如下:


public class UserDaoImpl extends AbstractHibernateDao implements UserDao
{
public UserDaoImpl()
{
super(PersonPO.class);
}
public PersonPO findUserByNameAndPassword(String name,String password)
{
return null; //todo
}
}

这里我们需要继承AbstractHibernateDao,同时提供entity的类型信息,同时创建一个默认的构造函数,然后调用AbstractHibernateDao的构造方法,进行entity类型赋值,这样UserDao的实现就完成了。

这里因为使用了Spring,接下来只需在Spring的配置文件中将UserDaoImpl进行声明定义即可。在你取得UserDao接口后,再调用的方式就完全以前不一样了,这里包含了entity的类型信息,而这以前都是Object类型,还需要了提供entity类的类型名称。下面的这两张图的对比相信你会看的一目了然。

使用Java 5 Generics特性定义的DAO

AppFuse中定义的DAO(传统的DAO模式)

总结:通过引入Java 5的Generics,再回头设计一下DAO,你会发现有些事情处理起来方便很多,在以前,我们只能获取Object对象,现在我们完全可以获取指定类型的对象啦,操作和理解都方便啦。关于AbstractDao你可能有自己的想法,你可以根据具体情况更改一些,如添加Spring的Annotation Transaction,这样对事务控制也会简单很多;如将添加分页功能,关于分页,请参考本站关于分页的文章:分页,心中的痛?。

 

你可能感兴趣的:(Hibernate, Java 5 and DAO)