รู้เบื้องต้นเกี่ยวกับ DAO
เมื่อทำงานกับฐานข้อมูลผ่าน JDBC หรือแม้แต่ผ่าน Hibernate โค้ดมักจะยุ่งยากกว่าที่เราต้องการ แบบสอบถามฐานข้อมูลมักจะประกอบด้วย:
- การตรวจสอบข้อมูล
- การตั้งค่าพารามิเตอร์คำขอ
- การเลือกเคียวรี HQL ขึ้นอยู่กับพารามิเตอร์เคียวรี
- สร้างแบบสอบถามโดยใช้ Criteria API
- การตั้งค่าแคช
- การจัดการข้อผิดพลาดเบื้องต้น เป็นต้น
ดังนั้นแนวทางปฏิบัติทั่วไปคือการสร้างคลาสพิเศษสำหรับการทำงานกับฐานข้อมูล คลาสดังกล่าวเรียกว่า DAO, Data Access Object งานของพวกเขาคือการซ่อนความซับซ้อนทั้งหมดของการทำงานกับฐานข้อมูลและจัดเตรียมส่วนต่อประสานที่สวยงามและสะดวกสบายให้กับภายนอก
ตัวอย่าง:
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 (รหัสยาวสุดท้าย) | รับวัตถุตามรหัสของมัน |
รายการ <T> getItems (int จาก, จำนวน int) | รับรายการวัตถุในช่วงที่กำหนด |
รายการ<T> getAll () | รับวัตถุทั้งหมดตามประเภทที่กำหนด |
int getCount () | ค้นหาจำนวนของวัตถุ |
T บันทึก (เอนทิตี T สุดท้าย) | บันทึกวัตถุลงในฐานข้อมูล |
T อัปเดต (เอนทิตี T สุดท้าย) | อัปเดตวัตถุในฐานข้อมูล |
โมฆะลบ (เอนทิตี T สุดท้าย) | ลบวัตถุออกจากฐานข้อมูล |
เป็นโมฆะdeleteById (รหัสเอนทิตียาวสุดท้าย) | ลบวัตถุออกจากฐานข้อมูลด้วย id |
วิธีการเหล่านี้พบได้ใน DAO เกือบทุกชั้นในโลก ตอนนี้ ถ้ามีคลาส DAO อยู่บ้าง ด้วยความน่าจะเป็น 90% ก็จะมีเมธอดดังกล่าว
ใช่ อาจมีคนอื่น แต่ก็จะมีคนเหล่านั้นด้วย เพราะมันสะดวกมาก และช่วยให้คุณไม่โต้ตอบกับฐานหรือไฮเบอร์เนตโดยตรง
และถ้ามีวิธีการที่เหมือนกัน พวกเขาต้องการอะไร? ถูกต้อง วางไว้ในคลาสพื้นฐาน
ดูเหมือนว่า:
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 การรวมกันนั้นสะดวกและใช้งานได้จริง