Здравствуйте, я хотел бы узнать как профессионально написать доступ к БД.
В интернете видел такие указания.
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
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
// dao without inheritance from IDao
interface IEntityBDao {
// find entity by name and user id
EntityB get(String name, String userId) throws DaoException;
List
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
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 по функционалу)
Комментариев нет:
Отправить комментарий