รู้เบื้องต้นเกี่ยวกับ 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 การรวมกันนั้นสะดวกและใช้งานได้จริง