Search code examples
javaspringhibernatespring-mvcspring-transactions

Hibernate and Spring DataSourceTransactionManager


I'm trying to work with Hibernate and Spring DataSourceTransactionManager to handle commit and rollback functions, but probably I dind't get something.

Before using Spring DataSourceTransactionManager, this was one of my DAO class

  package com.springgestioneerrori.DAO;

  public class UtenteDAO extends DAOBase{   

       public void salvaUtente(Utente utenteIn) throws DAOException{ 

            Session session = getHibernateSession(); //from this method  I get Hibernate SessionFactory
              try{   
                  session.beginTransaction();             
                  session.saveOrUpdate(Object); 
                  session.getTransaction().commit();    
                  }
              catch(Exception e){
                  session.getTransaction().rollback()
              }
        }
}

This is the class that give me the sessionFactory

 private static final SessionFactory sessionFactory = buildSessionFactory();

            private static SessionFactory buildSessionFactory() {
                try {
                    // Create the SessionFactory from hibernate.cfg.xml
                    return new AnnotationConfiguration().configure().buildSessionFactory();  
                }
                catch (Throwable ex) {
                              System.err.println("Initial SessionFactory creation failed." + ex);
                    throw new ExceptionInInitializerError(ex);
                }
            }

            public static SessionFactory getSessionFactory() {
                return sessionFactory;
            }

            public static void shutdown() {             
                getSessionFactory().close();
            }

public Session getHibernateSession (){
    Session session = HibernateUtil.getSessionFactory().openSession();
    return session;
}   

Now i'm trying to use DataSourceTransactionManager in a declarative way. Following some examples on the internet I wrote this:

 <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" />        

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="salvaUtente"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="userDaoTxPointcut" expression="execution(* com.springgestioneerrori.DAO.UtenteDAO.salvaUtente(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="userDaoTxPointcut" />
</aop:config>       

Now, what should I write inside the method salvaUtente() to perform many inserts, for example like these

  session.saveOrUpdate(User); 
  session.saveOrUpdate(UserCredentials); 
  session.saveOrUpdate(UserOtherDetails); 

and making Spring handle commint and rollback?


Solution

  • First you are using the wrong transaction manager. The DataSourceTransactionManager isn't for Hibernate but for plain JDBC. If you are using plain Hibernate use the HibernateTransactionManager. (Assuming that you are using Hibernate 4 here!).

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    

    Now I would also suggest to use @Transactional instead of a <tx:advice /> and <aop:config /> block. Makes your configuration easier. Simply remove the 2 mentioned blocks and replace with <tx:annotation-driven />.

    <tx:annotation-driven />
    

    Now your code is wrong as you are starting transactions yourself. Annotate your method with @Transactional (after adding the thing above) and remove your transaction handling code.

    @Transactional
    public void salvaUtente(Utente utenteIn) throws DAOException{ 
        Session session = getHibernateSession(); //from this method  I get Hibernate SessionFactory
        session.saveOrUpdate(Object); 
    }
    

    Now I don't know what your getHibenateSession method does but make sure you don't use openSession on the SessionFactory to obtain a session. Use getCurrentSession instead.

    protected Session getHibernateSession() {
        return sessionFactory.getCurrentSession();
    }
    

    Your current BaseDAO class is flawed. Delete your buildSessionFactory and remove the static final. Let Spring configure and inject the SessionFactory.

    public abstract class BaseDAO {
    
        @Autowired
        private SessionFactory sessionFactory;
    
        protected Session getHibernateSession() {
            return sessionFactory.getCurrentSession();
        }
    }
    

    In your configuration add the configuration for the LocalSessionFactoryBean.

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        ... Other Hibernate Properties
    </bean>
    

    That is basically all that is needed. This is also all explained in detail in the Spring Reference guide. I strongly suggest a read.