简体   繁体   中英

Some doubts about how implement Hibernate DAO in Spring applications

I am quite new in Spring world and I am trying to develop a DAO integrating Spring with Hibernate. I have create a working project but I have some architectural doubt about it.

I have create my Spring + Hibernate project basing it on the following standalone Hibernate tutorial (standalone because it don't use Spring or other framework, it is a simple Java + Hibernate project): http://www.tutorialspoint.com/hibernate/hibernate_examples.htm

In my project I have an interface in which I define all the CRUD method that I need and a concrete implementation of this interface, this one is the code of my concrete class:

package org.andrea.myexample.HibernateOnSpring.dao;

import java.util.List;

import org.andrea.myexample.HibernateOnSpring.entity.Person;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.springframework.transaction.annotation.Transactional;

public class PersonDAOImpl implements PersonDAO {

    // Factory per la creazione delle sessioni di Hibernate:
    private static SessionFactory sessionFactory;

    // Metodo Setter per l'iniezione della dipendenza della SessionFactory:
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /** CREATE CRUD Operation:
     * Aggiunge un nuovo record rappresentato nella tabella rappresentato
     * da un oggetto Person
     */
    @Transactional(readOnly = false)
    public Integer addPerson(Person p) {

        System.out.println("Inside addPerson()");

        Session session = sessionFactory.openSession();

        Transaction tx = null;
        Integer personID = null;

        try {
            tx = session.beginTransaction();

            personID = (Integer) session.save(p);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null)
                tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

        return personID;

    }

    // READ CRUD Operation (legge un singolo record avente uno specifico id):
    public Person getById(int id) {

        System.out.println("Inside getById()");

        Session session = sessionFactory.openSession();

        Transaction tx = null;          
        Person retrievedPerson = null;  

        try {
            tx = session.beginTransaction();
            retrievedPerson = (Person) session.get(Person.class, id);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {                 
            session.close();
        }

        return retrievedPerson;
    }

    // READ CRUD Operation (recupera la lista di tutti i record nella tabella):
    @SuppressWarnings("unchecked")
    public List<Person> getPersonsList() {

        System.out.println("Inside getPersonsList()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;
        List<Person> personList = null;

        try {
            tx = session.beginTransaction();
            Criteria criteria = session.createCriteria(Person.class);
            personList = criteria.list();
            System.out.println("personList: " + personList);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }
        return personList;
    }

    // DELETE CRUD Operation (elimina un singolo record avente uno specifico id):
    public void delete(int id) {

        System.out.println("Inside delete()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();
            Person personToDelete = getById(id);
            session.delete(personToDelete);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

    @Transactional
    public void update(Person personToUpdate) {

        System.out.println("Inside update()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            System.out.println("Insite update() method try");
            tx = session.beginTransaction();
            session.update(personToUpdate);

            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }   

    }

}

1) The first doubt is related to the fact that in this class, for each CRUD method I open a new session .

I have do in this way because in this tutorial: http://www.tutorialspoint.com/hibernate/hibernate_sessions.htm I have read that:

The Session object is lightweight and designed to be instantiated each time an interaction is needed with the database. Persistent objects are saved and retrieved through a Session object. The session objects should not be kept open for a long time because they are not usually thread safe and they should be created and destroyed them as needed.

But then someone say me that integrating Spring and Hibernate I don't need to open a new session in each CRUD method because if I add the @Transactional annotation to all the CRUD method the session that has been associated to the current transaction by Spring, and that will also be closed by Spring at the end of the transaction. It's Spring which will open and close a session each time a transaction is opened/closed.

So, if it is true, I have to open a session only one time and then get the current session.

Is it true or my concrete class it is right (it work well but I don't know if it work in a stupid way !!!)

2) The second doubt is related to the fact that reading the Spring documentation: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#orm-hibernate I find that it use AOP services that tin turn call the DAO...

So...is it my architecture so bad? I have an interface that rappresent my DAO and my concrete class that implement DAO using Hibernate and I call it's method to do CRUD operation on the DB

Regarding #1. Yes you do not need to explicitly handle the opening and closing of sessions when you use an @Transactional annotation in CRUD operation method of the DAO. Spring does that for you. All you need to do inside that is call the CRUD method on the current session, which is obtained by calling sessionFactory.getCurrentSession() . There is no need to explicitly open, commit and rollback the transactions as you have done in the above code. Spring will do that for you when you annotate the method with @Transactional .

Regarding #2. Spring has its own way of getting to your DAO implementation. It might be using AOP. That doesn't mean that your architecture is wrong. Your architecture using the Interface and Concrete Class implementation is the correct way to go. What I will do is make all the CRUD operations implemented by a Base Class and then let the subclass implement the DAO Specific method. What I meant is this (giving psuedo-code only):

interface BaseDAO {//declare all the CRUD methods}

interface PersonaDAO extends BaseDAO {//declare all Person related methods like getPersonsList}

class BaseDAOImpl implements BaseDAO {//CRUD method implementations }

class PersonaDAOImpl extends BaseDAOImpl implements PersonDAO {//implementation of Person related methods}

This, I feel will be a better arch, so that you can reuse the CRUD operations code. hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM