java-ee – How to write DAO correctly?

Question:

Hello, I would like to learn how to write DB access professionally.

I saw such instructions on the Internet.

1. Write an interface

public interface MyObjDAO {
    public void save(MyObj object);
    public MyObj getById(int id);
    ...
}

2. Write an implementation. I am using Hibernate library.

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());
        .....
        .....
    }
}

My questions are:

  1. If I use access to the database in a WEB application (in which several users require access at the same time), do I need to synchronize access methods?
  2. Is it correct to create Hibernate config and builder in accessor methods (or could it be correct to create singleton class to issue session)
  3. Well, in general, I would like to hear the opinion of people with experience on how to do it correctly.

I apologize for the lame questions, but I could not find an unambiguous answer on the Internet.


UPD. So the answer to my question number 2 is

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 (ie 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.

Therefore, the SessionFactory must be 1 per application.


UPD2 Regarding synchronization. SessionFactory is fully synchronized. And the session itself must be created in each thread independently.


UPD3 If anyone is interested. To obtain a session object, it is recommended to use the Open Session in View pattern, which, in fact, represents a servlet filter that opens a session and controls the transaction commit for all other servlets. In this way, the LazyInitializationException is easily avoided. But I don't like this option, since sessions are created for all servlets, so when one page is opened, the session is repeatedly opened and closed, even for those servlets that are not related to the database.


UPD4 Accidentally came across an interesting article Do not repeat DAO! , but there it is mixed with spring, although I like the idea of ​​a generic dao!

Answer:

For a long time, we have been using the following hierarchy of objects in our applications to implement work with a DBMS:

1) hierarchy for entities – each entity describes one table, they have a common ancestor so that you can easily identify all objects) + add some common functionality (at least override the toString () method). If additional functionality is not needed, then you can use the interface:

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) any auxiliary classes (in this case, only its own type of error):

class DaoException extends Exception {
}

3) DAO hierarchy: interface with generic methods (optionally added to the specific DAO interface):

interface IDao<T extends ABaseDaoEntity> {

    // 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 hierarchy: general abstract class: it is needed in order to add common functionality to all dao (in your case, only a reference to the session factory object), in addition to this, there should also be implementations of IDao methods if this code is universal for any entity . When using frameworks, this is often the case, at least for methods: create , update , delete

abstract class ABaseDao<T extends ABaseDaoEntity> implements IDao<T> {
    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 hierarchy: dao interfaces of objects, in fact, only find methods need to be declared here, since you can add the rest simply by adding inheritance from the IDao interface (obviously, only if necessary):

// dao with inheritance from IDao
interface IEntityADao extends IDao<EntityA> {

    List<EntityA> 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<EntityB> findAll() throws DaoException;
}

6) DAO hierarchy: examples of DAO implementations:

// concrete dao for EntityA
class EntityADao extends ABaseDao<EntityA> 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<EntityB> implements IEntityBDao {

    public EntityBDao(SessionFactory factory) {
        super(factory);
    }

    // implementations of the EntityB DAO methods

}

ps missed an important detail:

7) DAO factory: needed in order to access a specific DAO object:

interface IDaoFactory {
  IEntityADao getEntityADao();
  IEntityBDao getEntityBDao();
}
class DaoFactory implements IDaoFactory {
  // implementations of all methods
}

ps if DAO stateless objects (by functionality) – you can create them with each call of the getter, but if statefull , then you can create them when creating a DaoFactory object and then return links to objects (you can use lazy loading)

8) IDaoFactoryBean, DaoFactoryBean – interface (optional) and implementation of the bean, which is actually responsible for creating and providing access to the DAOFactory . it should be an EJB component, singleton

interface IDaoFactoryBean {
    IDaoFactory getDaoFactory();
}

ps if the creation of a session factory is a complicated process or there is a need to change it frequently, then it is better to move the creation of this object into a separate singleton ejb. in this case, the DaoFactoryBean bean can be made stateless if DaoFactory also stateless (I mean not ejb stateless but in terms of functionality)

Scroll to Top