DAO'ya Giriş
JDBC ve hatta Hibernate aracılığıyla bir veritabanıyla çalışırken, kod genellikle istediğimizden daha hantal hale gelir. Bir veritabanı sorgusu genellikle şunları içerir:
- veri doğrulama
- istek parametrelerini ayarlama
- Sorgu parametrelerine bağlı olarak HQL sorgu seçimi
- Criteria API kullanarak sorgu oluşturma
- önbelleğe alma ayarları
- ilk hata işleme vb.
Bu nedenle, yaygın uygulama, veritabanıyla çalışmak için özel sınıflar oluşturmaktır. Bu tür sınıflara DAO, Data Access Object denir. Görevleri, veritabanıyla çalışmanın tüm karmaşıklıklarını gizlemek ve dışarıya güzel ve kullanışlı bir arayüz sağlamaktır.
Örnek:
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();
}
}
Veritabanından Çalışan türündeki nesneleri aldığımız bir ÇalışanDAO sınıfımız var . Sınıfın kendisi, ek açıklamalarla dolu olmasına rağmen, kendisini veritabanına kaydetmek için yöntemler içermez.
DAO'nun Faydaları
Bu yaklaşımın birçok avantajı vardır:
Öncelikle veritabanı ile çalışmayı DAO sınıfında tamamen gizledik. Gelecekte tüm sorguları HQL'den Criteria API'ye veya Native Query'ye yeniden yazmaya karar verirseniz, bu, bu sınıfın dışındaki kodu hiçbir şekilde etkilemeyecektir.
İkinci olarak, bu yöntemlerin davranışını karmaşıklaştırabilirsiniz. Önbelleğe alma, olaylar, parametre doğrulama ekleyebilirsiniz. Bunların hepsi dış koddan gizlenecektir.
Üçüncüsü, henüz var olmayan bir yönteme ihtiyacınız varsa, onu buraya eklemeniz yeterli. Örneğin, süresi dolmuş tüm kullanıcı görevlerini döndürecek bir yönteme ihtiyacım var. O zaman sadece şunu yapacağım:
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();
}
}
Sınıfa iki yöntem ekledim:
- getExpiredTasksCount() - kullanıcı için süresi dolan görevlerin sayısını döndürür
- getExpiredTasks() - kullanıcı için süresi dolmuş görevlerin bir listesini döndürür
Yöntemlere ihtiyacım var - onları ekledim. Ve hemen kullanabilirim. Onları daha sonra optimize edeceğim.
Ayrıca, bu yöntemler yeniden yazma ve optimizasyonlardan önce birim testleri ile kapsanabilir, böylece veritabanı ile çalışmanın eskisi gibi kaldığını bileceğiz.
Standart Yaklaşım
Çoğu zaman, DAO sınıfları aynı olan yöntemlere sahiptir. Örneğin, bunlar:
T getById (son uzun kimlik) | kimliğine göre bir nesne alın |
List<T> getItems (int kaynağından, int sayısı) | Belirli bir aralıktaki nesnelerin listesini alın |
Liste<T> getAll () | Belirli bir türdeki tüm nesneleri al |
int getCount () | Nesnelerin sayısını öğrenin |
T kaydetme (son T varlığı) | Nesneyi veritabanına kaydet |
T güncellemesi (son T varlığı) | Veritabanındaki nesneyi güncelle |
geçersiz silme (son T varlığı) | Veritabanından bir nesneyi silme |
geçersiz deleteById (son uzun entityId) | Kimliğe göre veritabanından nesneyi sil |
Bu yöntemler dünyadaki hemen hemen her DAO sınıfında bulunur. Şimdi, bir tür DAO sınıfı varsa, o zaman %90 olasılıkla bu tür yöntemlere sahip olacaktır.
Evet, başkaları da olabilir ama onlar da olacak. Çünkü çok uygun. Ve doğrudan baz veya Hazırda Bekletme ile etkileşime girmemenizi sağlar.
Ve aynı yöntemler varsa, neye ihtiyaçları var? Bu doğru, temel sınıfa koyun.
Şunun gibi görünüyor:
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();
}
}
Ardından, ÇalışanDAO'muz şöyle görünecek:
public class EmployeeDAO extends AbstractHibernateDAO<Employee> {
public EmployeeDAO (){
super(Employee.class );
}
}
Ve TaskDAO şöyle:
public class TaskDAO extends AbstractHibernateDAO<Task> {
public TaskDAO (){
super(Task.class );
}
}
Ve bu sınıfların her ikisi de, AbstractHibernateDAO'da bildirdiğimiz tüm yöntemlere sahip olacak . Birleştirme çok uygun ve pratiktir.