Introduktion till DAO
När man arbetar med en databas via JDBC eller till och med via Hibernate visar sig koden ofta vara mer krånglig än vad vi skulle vilja. En databasfråga innehåller ofta:
- datavalidering
- ställa in parametrar för begäran
- HQL-frågeval beroende på frågeparametrar
- konstruera en fråga med Criteria API
- cachningsinställningar
- initial felhantering etc.
Därför är den vanliga praxisen att skapa specialklasser för att arbeta med databasen. Sådana klasser kallas DAO, Data Access Object. Deras uppgift är att dölja all komplexitet med att arbeta med databasen och tillhandahålla ett vackert och bekvämt gränssnitt utåt.
Exempel:
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 klass EmployeeDAO , med hjälp av vilken vi hämtar objekt av typen Employee från databasen. Själva klassen, även om den är fylld med kommentarer, innehåller inte metoder för att spara sig själv i databasen.
Fördelar med DAO
Det finns många fördelar med detta tillvägagångssätt:
Först har vi helt dolt arbetet med databasen i DAO-klassen. Om du i framtiden bestämmer dig för att skriva om alla frågor från HQL till Criteria API eller Native Query, kommer detta inte att påverka koden utanför denna klass på något sätt.
För det andra kan du komplicera beteendet hos dessa metoder. Du kan lägga till cachning, händelser, parametervalidering. Allt detta kommer att döljas från den yttre koden.
För det tredje, om du behöver en metod som inte finns ännu, lägger du bara till den här. Till exempel behöver jag en metod som returnerar alla användaruppgifter som redan har löpt ut. Då gör jag bara så här:
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();
}
}
Jag lade till två metoder till klassen:
- getExpiredTasksCount() - returnerar antalet utgångna uppgifter för användaren
- getExpiredTasks() - returnerar en lista med utgångna uppgifter för användaren
Jag behöver metoder - jag har lagt till dem. Och jag kan använda den direkt. Jag kommer att optimera dem senare.
Dessutom kan dessa metoder täckas med enhetstester före omskrivning och optimeringar, så vi vet att arbetet med databasen har förblivit detsamma som det var.
Standardmetoden
Mycket ofta har DAO-klasser metoder som är desamma. Till exempel dessa:
T getById (slutligt långt id) | Få ett objekt efter dess id |
Lista<T> getItems (int from, int count) | Få en lista över objekt inom ett givet intervall |
Lista<T> getAll () | Få alla objekt av en given typ |
int getCount () | Ta reda på antalet föremål |
T spara (slutlig T-enhet) | Spara objekt i databasen |
T- uppdatering (slutlig T-enhet) | Uppdatera objekt i databasen |
ogiltig radering (slutlig T-enhet) | Ta bort ett objekt från databasen |
void deleteById (slutligt långt enhets-ID) | Ta bort objekt från databasen med id |
Dessa metoder finns i nästan alla DAO-klasser i världen. Nu, om det finns någon slags DAO-klass, så kommer den med 90% sannolikhet att ha sådana metoder.
Ja, det kan finnas andra, men det kommer att finnas de också. För det är väldigt bekvämt. Och det låter dig inte interagera med basen eller viloläge direkt.
Och om det finns identiska metoder, vad behöver de då? Just det, lägg det i basklassen.
Det ser ut ungefär så här:
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();
}
}
Och då kommer vår EmployeeDAO att se ut så här:
public class EmployeeDAO extends AbstractHibernateDAO<Employee> {
public EmployeeDAO (){
super(Employee.class );
}
}
Och TaskDAO är så här:
public class TaskDAO extends AbstractHibernateDAO<Task> {
public TaskDAO (){
super(Task.class );
}
}
Och båda dessa klasser kommer att ha alla metoder som vi deklarerade på AbstractHibernateDAO . Enande är mycket bekvämt och praktiskt.