首页 > 代码库 > 通用Hibernate-Dao

通用Hibernate-Dao

在做管理系统时。通常基于Facade模式的系统持久化层要写许多Dao。这些dao里面的方法又是重复的,那么有没有什么好的方法来统一利用一个公共的Dao。 

答案是可以的。这里我们接触到JDK5.0里面的一个新特性:泛型。 

关于泛型的含义我这里就不再解释了。 

下面我们以一个对用户管理和新闻管理的来示范。 

首先是2个POJO。我这里只列出User  POJO。 
(基于注释的Pojo)

package com.oa;  
  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.GenerationType;  
import javax.persistence.Id;  
import javax.persistence.Table;  
  
@Entity  
@Table(name = "tb_user")  
public class User {  
  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private int id;  
  
    @Column(name = "username", length = 15)  
    private String username;  
  
    @Column(name = "password", length = 15)  
    private String password;  
  
    public int getId() {  
        return id;  
    }  
  
    public void setId(int id) {  
        this.id = id;  
    }  
  
    public String getUsername() {  
        return username;  
    }  
  
    public void setUsername(String username) {  
        this.username = username;  
    }  
  
    public String getPassword() {  
        return password;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
  
}  
  
 

如果按照常规的Facade模式来设计,我们的思路是: 
先创建一个UserDao的接口。 

package com.oa.dao;  
  
import java.util.List;  
  
import com.oa.User;  
  
public interface UserDao {  
    public void save(User user);  
  
    public void delete(int id);  
  
    public void update(User user);  
  
    public List<User> query();  
  
    public User get(int id);  
  
}  
  

然后实现这个接口:UserDaoImpl 

package com.oa.dao.impl;  
  
import java.util.List;  
  
import org.springframework.context.annotation.Scope;  
import org.springframework.stereotype.Repository;  
  
import com.oa.User;  
import com.oa.dao.MyHibernateDaoSupport;  
import com.oa.dao.UserDao;  
  
  
  
/** 
 * 从Spring 2.0开始,引入了@Repository注解, 
 *  用它来标记充当储存库(又称 Data Access Object或DAO)角色或典型的类 
 */  
  
  
/** 
 * Spring 2.5引入了更多典型化注解(stereotype annotations): @Component、@Service和 @Controller。  
 * @Component是所有受Spring管理组件的通用形式; 而@Repository、@Service和 @Controller则是@Component的细化,  
 *                   用来表示更具体的用例(例如,分别对应了持久化层、 服务层  和   表现层)。 
 */  
//@Scope("singlton")  
@Repository("userDao")//声明此类为数据持久层的类  
public class UserDaoImpl extends MyHibernateDaoSupport implements UserDao {  
  
    public void delete(int id) {  
        super.getHibernateTemplate().delete(  
                super.getHibernateTemplate().load(User.class, id));  
  
    }  
  
    public User get(int id) {  
  
        return (User) super.getHibernateTemplate().get("from  User", id);  
    }  
  
    @SuppressWarnings("unchecked")  
    public List<User> query() {  
        return super.getHibernateTemplate().find("from User");  
  
    }  
  
    public void save(User user) {  
        super.getHibernateTemplate().save(user);  
  
    }  
  
    public void update(User user) {  
        super.getHibernateTemplate().update(user);  
  
    }  
  
}  

持久化层完毕。 


接下来的是事务层 


先创建一个UserService的接口

package com.oa.service;  
  
import com.oa.User;  
  
public interface UserService {  
      
    public void save(User user);  
  
    public void update(User user);  
  
}  

然后实现这个接口:UserServiceImpl。 
在UserServiceImpl里引用UserDao来实现业务逻辑。 

package com.oa.service.impl;  
  
import com.oa.User;  
import com.oa.service.UserService;  
import com.oa.dao.UserDao;  
  
  
import java.util.List;  
  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  
  
  
  
/** 
 * 声明此类为业务逻辑层的类 
 * 默认bean名称生成器会返回小写开头的非限定(non-qualified)类名 
 * @Service 
 * userServiceImpl 
 */  
@Service("userService")  
public class UserServiceImpl implements UserService {  
  
      
    /** 
     * @Autowired 
     *  
     * @Autowired 注解可以用于"传统的"setter 方法,如下例: 
     * public void setUserDao(UserDAO userDao) 
    { 
        this.userDao = userDao; 
    } 
     */  
      
    /** 
     * @Resource有一个‘name‘属性,缺省时,Spring 将这个值解释为要注射的 bean 的名字。 
     *   @Resource(name="userDao")  
     */  
    @Autowired //  or  @Resource(name="userDao")  
    private UserDao userDao;  
  
    public void save(User user) {  
        userDao.save(user);  
  
    }  
  
    public void update(User user) {  
        userDao.update(user);  
  
    }  
  
}  
  
   

按照上面的模式:新闻管理也这么写一遍。 

重复的工作使得我们觉得好烦。 


这个时候是泛型出场的时候了。 

基于Facade的设计模式,dao和service还是要的。 这里我们就要设计一个公共的Dao..  我们称之为:GenericDao 

package com.oa.dao;  
  
import java.io.Serializable;  
import java.util.*;  
  
/** 
 * * 
 *  
 * @param <T> 
 *            泛型,指实体类  type 
 * @param <PK> 
 *            泛型,指实体类主键的数据类型,如Integer,Long 
 */  
public interface GenericDao<T, PK> {  
      
    /**   
     * 保存指定实体类   
     *    
     * @param entityobj   
     *            实体类   
     */   
    public  void save(T entity);  
      
      
      /**   
     * 删除指定实体   
     *    
     * @param entityobj   
     *            实体类   
     */    
    public void delete(T entity);  
      
      
     /** * 
     * 删除实体 
     * @param entityClass 实体类名 
     * @param id 实体的ID 
     */  
    public void deleteById(Class<T> entityClass,PK id);  
      
      
    /**   
    * 更新或保存指定实体   
    *    
    * @param entity 实体类   
    */   
    public void saveorupdate(T entity);  
      
      
     /** * 
     * 更新实体 
     * 可用于添加、修改、删除操作 
     * @param hql 更新的HQL语句 
     * @param params 参数,可有项目或多项目,代替Hql中的"?"号 
     */  
    public void update(final String hql,final Object[] params);  
      
      
  
    /**   
     * 模糊查询指定条件对象集合 <br>   
     * 用法:可以实例化一个空的T对象,需要查询某个字段,就set该字段的条件然后调用本方法<br>   
     * 缺点:目前测试貌似只能支持String的模糊查询,虽然有办法重写,但没必要,其他用HQL<br>   
     *    
     * @param entity   
     *            条件实体   
     * @return 结合   
     */    
    public List<T> findByExample(T entity);  
      
      
    /**   
     * 获取所有实体集合   
     *    
     * @param entityClass   
     *            实体   
     * @return 集合   
     */    
    public List<T> findAll(Class<T> entityClass);  
      
    public List<T> findAll(Class<T> entityClass,String hql,Object[] params,int start, int limit);  
    /**   
     * 查找指定PK实体类对象   
     *    
     * @param entityClass   
     *            实体Class   
     * @param id   
     *            实体PK   
     * @return 实体对象   
     */     
    public T findById(Class<T> entityClass, PK id);  
      
    /** * 
     * 按HQL条件查询列表 
     * @param hql 查询语句,支持连接查询和多条件查询 
     * @param params 参数数组,代替hql中的"?"号 
     * @return 结果集List 
     */  
     
    public List<T> findByHql(String hql,Object[]  params);  
      
    /**   
     * 查找指定属性的实体集合   
     *    
     * @param entityClass   
     *            实体   
     * @param propertyName   
     *            属性名   
     * @param value   
     *            条件   
     * @return 实体集合   
     */    
    public List<T> findByProperty(Class<T> entityClass, String propertyName,Object value);  
      
      
    /**   
     * 查询指定HQL语句的分页数据集合   
     *    
     * @param hsql   
     *            HQL语句   
     * @param start   
     *            开始记录号   
     * @param limit   
     *            最大记录号   
     * @return 分页数据集合   
     * @throws Exception   
     *             抛出异常   
     */    
    public List<T> findByPage(Class<T> entityClass,int start,int limit) ;  
      
      
      
    /** 
     * 获得总记录数 
     */  
    public T getTotalCount(Class<T> entityClass);  
      
    public T getPageCount(String hql,Object[] params);  
  
}  
   

看到,我们不再是具体的User , News 
。。而是用 T  来取代实体。 


因为我这个是基于 注解的,所以附上MyHibernateDaoSupport的代码。 

package com.oa.dao;  
  
import javax.annotation.Resource;  
import org.hibernate.SessionFactory;  
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;  
  
/** 
 * 我们之所以要改写 
 * HibernateDaoSupport,是因我为,我们要为DAO层的类注入SessionFactory这个属性。 
 * 以后,我们开发的DAO类,就可以直接重用这个MyHibernateDaoSupport了。 
 * 其实,这样做是相当于配置文件方式的代码: 
 * <bean id="userDao" class="com.oa.dao.UserDaoImpl">  
 * <property 
 * name="sessionFactory" ref="sessionFactory"/>  
 * </bean> 
 *  
 * @author Administrator 
 *  
 */  
public class MyHibernateDaoSupport extends HibernateDaoSupport {  
      
    @Resource(name="sessionFactory")    //为父类HibernateDaoSupport注入sessionFactory的值  
    public void setSuperSessionFactory(SessionFactory sessionFactory){  
        super.setSessionFactory(sessionFactory);  
    }  
      
  
}  
  

到现在位置genericdao的接口有了,也就是我们要做什么。。现在就是实现它,就是怎么做。 
GenericDaoImpl 代码: 

package com.oa.dao.impl;  
  
import java.io.Serializable;  
import java.util.List;  
  
import org.hibernate.Query;  
import org.springframework.stereotype.Repository;  
  
import com.oa.dao.GenericDao;  
import com.oa.dao.MyHibernateDaoSupport;  
@SuppressWarnings("unchecked")  
@Repository("genericDao")   //声明此类为数据持久层的类  
public class GenericDaoImpl<T, PK extends Serializable> extends  
                                    MyHibernateDaoSupport implements GenericDao<T, PK> {  
  
    public void delete(T entity) {  
        super.getHibernateTemplate().delete(entity);  
    }  
  
  
    public void deleteById(Class entityClass, PK id) {  
        super.getHibernateTemplate().delete(findById(entityClass, id));  
  
    }  
      
    public void save(T entity) {  
        super.getHibernateTemplate().save(entity);  
  
    }  
  
    public void saveorupdate(T entity) {  
        super.getHibernateTemplate().saveOrUpdate(entity);  
  
    }  
  
    public void update(String hql, Object[] params) {  
             Query query = super.getSession().createQuery(hql);  
                for(int i=0; i<params.length; i++){  
                    query.setParameter(i, params[i]);  
                }  
                query.executeUpdate();  
     }  
      
  
    public List<T> findAll(Class entityClass) {  
          
        return super.getHibernateTemplate().loadAll(entityClass);  
    }  
  
    public List<T> findAll(Class entityClass, String hql, Object[] params,int start, int limit) {  
        Query query = super.getSession().createQuery(hql);  
        if(params!=null&&params.length>0){  
            for(int i = 0;i<params.length;i++){  
                query.setParameter(i, params[i]);  
            }  
        }  
        if(start!=0&&limit!=0){  
            query.setFirstResult(start).setMaxResults(limit);  
        }  
        return query.list();  
    }  
  
    public List<T> findByExample(T entity) {  
        return super.getHibernateTemplate().findByExample(entity);  
    }  
  
    public List<T> findByHql(String hql, Object[] params) {  
        Query query = super.getSession().createQuery(hql);  
        if(null!= params && params.length>0){  
            for(int i = 0; i<params.length;i++){  
                query.setParameter(i, params[i]);  
            }  
        }  
        return query.list();  
    }  
  
    public T findById(Class entityClass, PK id) {  
        return (T)super.getHibernateTemplate().get(entityClass, id);  
    }  
      
    public List<T> findByProperty(Class entityClass, String propertyName,Object value) {  
        String queryString = "from "+entityClass.getName()+ " as model where model." + propertyName + "=?";     
        return super.getHibernateTemplate().find(queryString, value);  
    }  
  
  
      
    //分页使用  
    public List<T> findByPage(Class<T> entityClass,int start,int limit) {  
          Query query=super.getSession().createQuery("select o from "+entityClass.getName()+" o");  
          query.setFirstResult(start).setMaxResults(limit);  
        return query.list();  
    }  
  
      
    public T getTotalCount(Class entityClass) {  
          
        return (T)super.getSession().createQuery("select count(o) from "+entityClass.getName()+" o").uniqueResult();  
    }  
  
    public T getPageCount(String hql, Object[] params) {  
        Query query = super.getSession().createQuery(hql);  
        if(null!= params && params.length>0){  
            for(int i = 0; i<params.length;i++){  
                query.setParameter(i, params[i]);  
            }  
        }  
        return (T)query.list();  
    }  
  
      
  
} 


至此 泛型就告一个段落。 


接下来日子就好过了。 

我们不是有user  news   等等一系列的curd管理。 


以User为例子; 
定义一个user的接口, 
UserDao.Java 

package com.oa.dao;  
  
import com.oa.User;  
  
public interface UserDao extends GenericDao<User, Integer> {  
  
public   int   login(User user);  
//其他的方法的  
}  
  
  
然后就是实现它 UserDaoImpl  
  
package com.oa.dao.impl;  
  
  
  
import com.oa.User;  
import com.oa.dao.UserDao;  
  
public class UserDaoImpl extends GenericDaoImpl<User, Integer> implements UserDao {  
  
    public  int  login(User  user){  
//登陆判断的方法  
  
return   XX;  
};  
  
  
//其他的方法的实现  
  
  
}  
  

持久化层就是这么多了。 

下面进入业务逻辑层,依然是先定义一个接口。 

package com.oa.service;  
  
import com.oa.User;  
  
public interface UserService {  
      
    public void save(User user);  
  
    public void update(User user);  
  
   public  int  login(User  user);  
  
//其他的方法  
  
}  


接下来是实现 

package com.oa.service.impl;  
  
import com.oa.User;  
import com.oa.dao. UserDao;  
import com.oa.service.TestUserService;  
  
public class UserService implements UserService {  
  
    private  UserDao  UserDao;  
    public void save(User user) {  
        UserDao.save(user);  
  
    }  
  
    public void updasaveorupdatete(User user) {  
        UserDao.saveorupdate(user);  
  
    }  
  
    public int   login(User user) {  
        return   UserDao.login(user);  
  
    }  
  
//其他的方法。。。。  
  
}  

Ok。。到现在我们就利用泛型dao来设计就完毕了 

两者相对比,发现dao层的代码可以复用,少了不少。 

对于大型管理系统,效果更明显。 

通用Hibernate-Dao