DAO简介

当通过 JDBC 甚至通过 Hibernate 使用数据库时,代码往往比我们想要的更麻烦。数据库查询通常包含:

  • 数据验证
  • 设置请求参数
  • 根据查询参数选择 HQL 查询
  • 使用 Criteria API 构建查询
  • 缓存设置
  • 初始错误处理等

因此,通常的做法是创建特殊的类来处理数据库。这样的类称为 DAO,数据访问对象。他们的任务是隐藏使用数据库的所有复杂性,并为外部提供一个美观方便的接口。

例子:

public class EmployeeDAO {

   public List<Employee> getEmployeeList(int from, int count) {
   	String hqlQuery = “from Employee;
   	Query<Employee> query = session.createQuery(hqlQuery, Employee.class);
   	query.setFirstResult(from);
   	query.setMaxResults(count);
   	return query.getResultList();
  }

	public int getEmployeeCount() {
	     String hqlQuery = “select count(*) from Employee;
     	Query<Integer> query = session.createQuery(hqlQuery, Integer.class);
     	return query.getSingleResult();
   }

	public Employee getEmployeeByUniqName(String name) {
	     String hqlQuery = “from Employee where name = :name”;
     	Query<Integer> query = session.createQuery(hqlQuery, Employee.class);
     	query.setParameterr(“name”, name);
     	return query.getSingleResult();
   }
}

我们有一个EmployeeDAO类,借助它我们可以从数据库中获取 Employee 类型的对象。该类本身虽然充满了注释,但不包含将自身保存到数据库的方法。

DAO 的好处

这种方法有很多优点:

首先,我们完全隐藏了 DAO 类中的数据库工作。如果您将来决定将所有查询从 HQL 重写为 Criteria API 或 Native Query,这不会以任何方式影响此类外部的代码。

其次,您可以使这些方法的行为复杂化。您可以添加缓存、事件、参数验证。这一切都将对外部代码隐藏。

第三,如果您需要一个尚不存在的方法,只需在此处添加即可。例如,我需要一个方法来返回所有已经过期的用户任务。然后我就这样做:

public class EmployeeDAO {

   public List<Task> getExpiredTasks(int userId, int from, int count) {
   	String hqlQuery = “from Task where task.user.id = :id and deadline < curdate();
   	Query<Task> query = session.createQuery(hqlQuery, Task.class);
   	query.setFirstResult(from);
   	query.setMaxResults(count);
   	return query.getResultList();
  }

   public int getExpiredTasksCount(int userId) {
   	String hqlQuery = “select count(*) from Task where task.user.id = :id and deadline < curdate();
   	Query<Integer> query = session.createQuery(hqlQuery, Integer.class);
   	return query.getSingleResult();
  }
}

我在类中添加了两个方法:

  • getExpiredTasksCount() - 返回用户的过期任务数
  • getExpiredTasks() - 返回用户的过期任务列表

我需要方法——我添加了它们。我可以马上使用它。我稍后会优化它们。

而且,这些方法可以在重写和优化之前用单元测试覆盖,所以我们会知道对数据库的工作仍然和以前一样。

标准方法

通常,DAO 类具有相同的方法。例如,这些:

T getById(最终长id) 通过 id 获取对象
List<T> getItems (int from, int count) 获取给定范围内的对象列表
列表<T> getAll () 获取给定类型的所有对象
int获取计数() 找出对象的数量
T保存(最终 T 实体) 将对象保存到数据库
T更新(最终T实体) 更新数据库中的对象
无效删除(最终 T 实体) 从数据库中删除对象
void deleteById (final long entityId) 通过id从数据库中删除对象

这些方法在世界上几乎每个 DAO 类中都有。现在,如果有某种 DAO 类,那么它有 90% 的可能性会有这样的方法。

是的,可能还有其他人,但也会有那些人。因为很方便。它允许您不直接与 base 或 Hibernate 交互。

如果有相同的方法,那么他们需要什么?没错,放在基类中。

它看起来像这样:

public abstract class AbstractHibernateDao<T > {
    private final Class<T> clazz;
    private SessionFactory sessionFactory;

    public AbstractHibernateDao(final Class<T> clazzToSet)   {
    	this.clazz = clazzToSet;
    }

    public T getById(final long id) {
    	return (T) getCurrentSession().get(clazz, id);
    }

    public List<T> getItems(int from, int count) {
    	Query query = getCurrentSession().createQuery(clazz , "from " + clazz.getName())
    	query.setFirstResult(offset);
    	query.setMaxResults(count);
  	  return query.singleResult();
    }

    public List<T> findAll() {
    	return getCurrentSession().createQuery(clazz, "from " + clazz.getName()).list();
    }

    public T create(final T entity) {
    	getCurrentSession().saveOrUpdate(entity);
    	return entity;
    }

    public T update(final T entity) {
    	return (T) getCurrentSession().merge(entity);
    }

    public void delete(final T entity) {
    	getCurrentSession().delete(entity);
    }

    public void deleteById(final long entityId) {
    	final T entity = getById(entityId);
    	delete(entity);
    }

    protected Session getCurrentSession() {
    	return sessionFactory.getCurrentSession();
    }
}

然后我们的EmployeeDAO将如下所示:

public class EmployeeDAO extends AbstractHibernateDAO<Employee> {

   public EmployeeDAO (){
  	super(Employee.class );
   }
}

TaskDAO是这样的:

public class TaskDAO extends AbstractHibernateDAO<Task> {

   public TaskDAO (){
  	super(Task.class );
   }
}

这两个类都将拥有我们在AbstractHibernateDAO上声明的所有方法。统一非常方便实用。