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上聲明的所有方法。統一非常方便實用。
GO TO FULL VERSION