Data Access Object (DAO). Уровень класса

от автора

При проектировании информационной системы выявляются некоторые слои, которые отвечают за взаимодействие различных модулей системы. Соединение с базой данных является одной из важнейшей составляющей приложения. Всегда выделяется часть кода, модуль, отвечающающий за передачу запросов в БД и обработку полученных от неё ответов. В общем случае, определение Data Access Object описывает его как прослойку между БД и системой. DAO абстрагирует сущности системы и делает их отображение на БД, определяет общие методы использования соединения, его получение, закрытие и (или) возвращение в Connection Pool.

Вершиной иерархии DAO является абстрактный класс или интерфейс с описанием общих методов, которые будут использоваться при взаимодействии с базой данных. Как правило, это методы поиска, удаление по ключу, обновление и т.д.

public abstract class AbstractController <E, K> {     public abstract List<E> getAll();     public abstract E getEntityById(K id);     public abstract E update(E entity);     public abstract boolean delete(K id);     public abstract boolean create(E entity); } 

Набор методов не является завершённым, он зависит от конкретной системы. Фиктивный тип K является ключом сущности, редкая таблица, описывающая сущность, не имеет первичного ключа. Так же, в данном классе будет логичным разместить метод закрытие экземпляра PrepareStatement.

public void closePrepareStatement(PreparedStatement ps) {         if (ps != null) {             try {                 ps.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }     } 

Уровень класса


Реализация DAO на уровне класса подразумевает использование одного единственного коннекта для вызова более чем одного метода унаследованного DAO класса. В этом случае, в вершине иерархии DAO AbstractController, в качестве поля объявляется connection. Абстрактный класс будет выглядеть следующим образом.

public abstract class AbstractController<E, K> {     private Connection connection;     private ConnectionPool connectionPool;      public AbstractController() {         connectionPool = ConnectionPool.getConnectionPool();         connection = connectionPool.getConnection();     }      public abstract List<E> getAll();     public abstract E update(E entity);     public abstract E getEntityById(K id);     public abstract boolean delete(K id);     public abstract boolean create(E entity);      // Возвращения экземпляра Connection в пул соединений     public void returnConnectionInPool() {         connectionPool.returnConnection(connection);     }      // Получение экземпляра PrepareStatement     public PreparedStatement getPrepareStatement(String sql) {         PreparedStatement ps = null;         try {             ps = connection.prepareStatement(sql);         } catch (SQLException e) {             e.printStackTrace();         }          return ps;     }      // Закрытие PrepareStatement     public void closePrepareStatement(PreparedStatement ps) {         if (ps != null) {             try {                 ps.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }     } } 


Стоит отметить, что в данном примере мы получаем экземпляр Connection из пула соединений, что соответственно стоит реализовать или воспользоваться уже готовыми решениями. Создаём методы по получению getPrepareStatement(String sql) и его закрытию closePrepareStatement(PreparedStatement ps) . Реализация конкретного DAO класса, при такой логике, никогда не должна закрывать в своих методах соединение с базой данных. Соединение закрывается в той части бизнес-логики, от куда был вызван метод. Пример конкретного DAO класса будет выглядеть следующим образом.

public class UserController extends AbstractController<User, Integer> {     public static final String SELECT_ALL_USERS = "SELECT * FROM SHEMA.USER";      @Override     public List<Planet> getAll() {         List<User> lst = new LinkedList<>();         PreparedStatement ps = getPrepareStatement(SELECT_ALL_PLANET);         try {             ResultSet rs = ps.executeQuery();             while (rs.next()) {                  User user = new User();                 planet.setId(rs.getInt(1));                 planet.setName(rs.getString(2));                 lst.add(user);             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             closePrepareStatement(ps);         }          return lst;     }      @Override     public Planet getEntityById(Integer id) {         return null;     }      @Override     public boolean delete(Integer id) {         return false;     }      @Override     public boolean create(Planet entity) {         return false;     } } 

Пример класса-сущности.

public class User implements Serializable {     private int id;     private String name;      public int getId() {         return id;     }      public void setId(int id) {         this.id = id;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      @Override     public String toString() {         return "User{" +                 "id=" + id +                 ", name='" + name + '\'' +                 '}';     } } 

Экземпляр Connection доступен методу getPrepareStatement(String sql), который в свою очередь доступен любому методу конкретного DAO класса. Стоит помнить, что следует закрывать экземпляр PrepareStatement сразу после его отработки в блоках finally, а возвращать соединение в пул returnConnectionInPool() в части логики системы, где был вызван метод.

ссылка на оригинал статьи http://habrahabr.ru/post/262243/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *