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上声明的所有方法。统一非常方便实用。