Страницы

Поиск по вопросам

понедельник, 12 ноября 2018 г.

Как правильно писать DAO ?

Здравствуйте, я хотел бы узнать как профессионально написать доступ к БД. В интернете видел такие указания. 1.Написать интерфейс public interface MyObjDAO { public void save(MyObj object); public MyObj getById(int id); ... } 2.Написать реализацию. Я использую библиотеку Hibernate. public class HibernateAccess implements MyObjDAO{
@Override public void save(MyObj object) { Configuration configuration = new Configuration().configure(); StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()); SessionFactory factory = configuration.buildSessionFactory(builder.build());
Session s = factory.openSession(); s.beginTransaction(); s.save(object); s.getTransaction().commit(); }
@Override public MyObj getById(int id){ Configuration configuration = new Configuration().configure(); StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()); SessionFactory factory = configuration.buildSessionFactory(builder.build()); ..... ..... } } У меня такие вопросы: Если я использую доступ к БД в WEB приложении (в котором одновременно несколько пользователей потребует доступ), нужно ли синхронизировать методы доступа ? Правильно ли создавать конфигурацию и билдер библиотеки Hibernate в методах доступа(или может быть правильно создать класс синглтон для выдачи сессии) Ну и вообще хотелось бы послушать мнение людей с опытом, как это делать правильно. Я прошу прощения за ламерские вопросы, но я не смог найти в интернете однозначного ответа. UPD. Итак, ответ на мой вопрос номер 2 SessionFactory is an extremely expensive process which involves parsing hibernate configuration/mapping properties and creating database connection pool .Creating a database connection pool requires establishing database connections (i.e creating Connection objects) which has overhead due to the time taken to locate the DB server , establish a communication channel and exchange information to do authentication. So if you create a SessionFactory for every request , it implies that you are not using database connection pool to serve your request .You have to setup a new connection by the above overheaded process for every request instead of just getting the opened connection from the database connection pool. Таким образом SessionFactory должен быть 1 на приложение. UPD2 По поводу синхронизации. SessionFactory полностью синхронизирован. А саму сессию в нужно создавать в каждом потоке независимо. UPD3 Если кому интересно. Для получения объекта сессии рекомендуют использовать паттерн Open Session in View, который, по сути, представляет сервлет-фильтр, открывающий сессию и контролирующий комит транзакции для всех остальных сервлетов. Таким образом легко избегается LazyInitializationException. Но мне такой вариант не нравится, так как сессии создаются для всех сервлетов, таким образом при открытии одной страницы происходит многократное открытие-закрытие сессии даже для тех сервлетов, которые не имеют отношения к БД. UPD4 Попал случайно на интересную статью Не повторяйте DAO!, но там она вперемешку со спрингом, хотя сама идея дженерик дао мне нравится!


Ответ

мы в своих приложениях уже длительное время используем примерно следующую иерархию обьектов для реализации работы с СУБД: 1) иерархия для entities - каждая ентити описывает одну таблицу, у них есть общий предок для того чтоб можно было легко идентифицировать все обьекты)+ добавить какой-то общий функционал (хотя бы метод toString() переопределить ). Если же дополнительного функционала не надо то можно использовать интерфейс: abstract class ABaseDaoEntity { }
class EntityA extends ABaseDaoEntity { private String id;
// getters,setters }
class EntityB extends ABaseDaoEntity { private String name; private String userId;
// getters,setters } 2) любые воспомагательные классы (в данном случае только свой тип ошибки): class DaoException extends Exception { } 3) иерархия DAO: интерфейс с общими методами (опционально добавляется к интерфейсу конкретного DAO): interface IDao {
// get by id void get(T entity) throws DaoException; T create(T entity) throws DaoException; void update(T entity) throws DaoException; void delete(T entity) throws DaoException; } 4) иерархия DAO: общий абстрактный класс: нужен для того чтоб добавить общий функционал всем дао (в вашем случае только ссылка на обьект session factory), помимо этого здесь же должны быть реализации методов IDao если этот код является универсальным для любой entity. При использовании фреймворков зачастую так и есть как минимум для методов: create, update, delete abstract class ABaseDao implements IDao { private SessionFactory factory;
public ABaseDao(SessionFactory factory) { setFactory(factory); }
protected SessionFactory getFactory() { return factory; } protected void setFactory(SessionFactory factory) { this.factory = factory; }
// here we may add implementation for common IDao methods // (if possible of course, - just in case implementation is the same for all types of entities) } 5) иерархия DAO: интерфейсы дао обьектов, по сути здесь необходимо обьявлять только методы find, т.к. добавить остальные можно просто добавив наследование от интерфейса IDao (очевидно что только при необходимости): // dao with inheritance from IDao interface IEntityADao extends IDao {
List findAll() throws DaoException; }
// dao without inheritance from IDao interface IEntityBDao {
// find entity by name and user id EntityB get(String name, String userId) throws DaoException;
List findAll() throws DaoException; } 6) иерархия DAO: примеры имплементаций DAO: // concrete dao for EntityA class EntityADao extends ABaseDao implements IEntityADao {
public EntityADao(SessionFactory factory) { super(factory); }
// implementations of the ABase DAO methods (required only)
// implementations of the EntityA DAO methods
}
// concrete dao for EntityB class EntityBDao extends ABaseDao implements IEntityBDao {
public EntityBDao(SessionFactory factory) { super(factory); }
// implementations of the EntityB DAO methods
} p.s упустил важную деталь: 7) DAO factory: нужны для того чтоб получать доступ к конкретному DAO обьекту: interface IDaoFactory { IEntityADao getEntityADao(); IEntityBDao getEntityBDao(); } class DaoFactory implements IDaoFactory { // implementations of all methods } p.s. если DAO stateless обьекты (по функционалу) - можно при каждом вызове геттера их создавать, если же statefull, то можно создать их при создании обьекта DaoFactory а потом уже возвращать ссылки на обьекты (можно применить lazy loading) 8) IDaoFactoryBean, DaoFactoryBean - интерфейс (опционально) и имплементация бина, который собственно и отвечает за создание и предоставление доступа к DAOFactory. это должна быть EJB компонента, singleton interface IDaoFactoryBean { IDaoFactory getDaoFactory(); } p.s. если создание session factory процес сложный или есть необходимость часто его менять то лучше создание этого обьекта вынести в отдельный singleton ejb. в этом случае бин DaoFactoryBean можно сделать stateless если DaoFactory тоже является stateless (имеется в виду не ejb stateless a по функционалу)

Комментариев нет:

Отправить комментарий