Introduktion til DAO
Når man arbejder med en database gennem JDBC eller endda via Hibernate, viser koden sig ofte at være mere besværlig, end vi gerne ville have. En databaseforespørgsel indeholder ofte:
- Data validering
- indstilling af anmodningsparametre
- Valg af HQL-forespørgsel afhængigt af forespørgselsparametre
- konstruere en forespørgsel ved hjælp af Criteria API
- cacheindstillinger
- indledende fejlhåndtering mv.
Derfor er den almindelige praksis at oprette særlige klasser til at arbejde med databasen. Sådanne klasser kaldes DAO, Data Access Object. Deres opgave er at skjule alt kompleksiteten ved at arbejde med databasen og give en smuk og praktisk grænseflade udadtil.
Eksempel:
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();
}
}
Vi har en klasse EmployeeDAO , ved hjælp af hvilken vi henter objekter af typen Employee fra databasen. Selve klassen, selvom den er fyldt med annoteringer, indeholder ikke metoder til at gemme sig selv i databasen.
Fordele ved DAO
Der er mange fordele ved denne tilgang:
For det første har vi fuldstændig skjult arbejdet med databasen i DAO-klassen. Hvis du i fremtiden beslutter dig for at omskrive alle forespørgsler fra HQL til Criteria API eller Native Query, vil dette på ingen måde påvirke koden uden for denne klasse.
For det andet kan du komplicere adfærden af disse metoder. Du kan tilføje caching, hændelser, parametervalidering. Alt dette vil være skjult fra den eksterne kode.
For det tredje, hvis du har brug for en metode, der ikke eksisterer endnu, skal du blot tilføje den her. For eksempel har jeg brug for en metode, der returnerer alle brugeropgaver, der allerede er udløbet. Så gør jeg bare dette:
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();
}
}
Jeg tilføjede to metoder til klassen:
- getExpiredTasksCount() - returnerer antallet af udløbne opgaver for brugeren
- getExpiredTasks() - returnerer en liste over udløbne opgaver for brugeren
Jeg har brug for metoder - jeg tilføjede dem. Og jeg kan bruge det med det samme. Jeg optimerer dem senere.
Desuden kan disse metoder dækkes med enhedstest før omskrivning og optimeringer, så vi ved, at arbejdet med databasen er forblevet, som det var.
Standard tilgang
Meget ofte har DAO-klasser metoder, der er de samme. For eksempel disse:
T getById (endelig lang id) | Få et objekt ved dets id |
List<T> getItems (int from, int count) | Få en liste over objekter inden for et givet område |
List<T> getAll () | Få alle objekter af en given type |
int getCount () | Find ud af antallet af objekter |
T save (endelig T-enhed) | Gem objekt i databasen |
T- opdatering (endelig T-enhed) | Opdater objekt i database |
ugyldig sletning (endelig T enhed) | Slet et objekt fra databasen |
void deleteById (endelig lang enheds-id) | Slet objekt fra database efter id |
Disse metoder findes i næsten alle DAO-klasser i verden. Nu, hvis der er en slags DAO-klasse, så vil den med 90% sandsynlighed have sådanne metoder.
Ja, der kan være andre, men der vil også være dem. Fordi det er meget praktisk. Og det giver dig mulighed for ikke at interagere med basen eller Hibernate direkte.
Og hvis der er identiske metoder, hvad har de så brug for? Det er rigtigt, sæt det i basisklassen.
Det ser sådan ud:
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();
}
}
Og så vil vores EmployeeDAO se sådan ud:
public class EmployeeDAO extends AbstractHibernateDAO<Employee> {
public EmployeeDAO (){
super(Employee.class );
}
}
Og TaskDAO er sådan her:
public class TaskDAO extends AbstractHibernateDAO<Task> {
public TaskDAO (){
super(Task.class );
}
}
Og begge disse klasser vil have alle de metoder, vi erklærede på AbstractHibernateDAO . Ensretning er meget praktisk og praktisk.
GO TO FULL VERSION