При проектировании информационной системы выявляются некоторые слои, которые отвечают за взаимодействие различных модулей системы. Соединение с базой данных является одной из важнейшей составляющей приложения. Всегда выделяется часть кода, модуль, отвечающающий за передачу запросов в БД и обработку полученных от неё ответов. В общем случае, определение 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/
Добавить комментарий