How to write a DAO correctly?


Hello, I would like to learn how to write database 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 use the 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());
        .....
        .....
    }
}

I have these questions:

  1. If I use DB access in a WEB application (where multiple users will require access at the same time), do I need to synchronize access methods ?
  2. Is it correct to create the configuration and builder of the Hibernate library in the access methods(or it may be correct to create a singleton class for issuing a session)
  3. Well, in general, I would like to hear the opinion of people with experience, how to do it correctly.

I apologize for the lamer questions, but I couldn't find a definitive 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 (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.

So the SessionFactory should be 1 per application.


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


UPD3 If anyone is interested. To get the session object, we recommend using the pattern Open Session in View, which is essentially a servlet filter that opens the session and controls the commit of the transaction for all other servlets. This way, the LazyInitializationException is easily avoided. But I don't like this option, since sessions are created for all servlets, so when opening one page, the session is repeatedly opened and closed, even for those servlets that are not related to the database.


UPD4 Hit accidentally on an interesting article Do not repeat DAO!, but there it is mixed with spring, although I like the idea of generic dao!

Author: wwvv, 2014-02-23

1 answers

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

1) hierarchy for entities - each entity describes one table, they have a common ancestor in order to easily identify all objects)+ add some general functionality (at least redefine the toString() method). If you do not need additional functionality, 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 recollection classes (in this case, only your own type of error):

class DaoException extends Exception {
}

3) DAO hierarchy: interface with common methods (optionally added to the interface of a specific DAO):

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) the DAO hierarchy: a common abstract class: needed in order to add common functionality to all daos (in your case, only a link to the object session factory), in addition, there must 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) the DAO hierarchy: the interfaces of the dao objects, in fact, here you need to declare only the find methods, since you can add the rest by simply 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) The 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

}

P. s 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
}

P. s. if the DAO stateless objects (by functionality) - you can create them every time the getter is called, but if statefull, you can create them when creating a DAOFactory object and then return references to the 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 DAOFactory. this should be the component's EJB, singleton

interface IDaoFactoryBean {
    IDaoFactory getDaoFactory();
}

P. s. if the creation of the session factory process complex or there is a need to change it often, then it is better to put the creation of this object in a separate singleton ejb. in this case, the DaoFactoryBean bin can be made stateless if DaoFactory is also stateless (meaning not ejb stateless a by functionality)

 9
Author: jmu, 2014-02-26 23:46:29