Hibernate spring annotation sessions not being closed/flushed

13,717

Solution 1

One of my cleverer colleagues discovered what the problem was.

The actual problem was that the method that you've declared as @Transactional is an inherited method that is called from a base class, which means that Spring is unable to intercept calls to the method and wrap it in a transaction.

Spring implements transaction management as aspects, and aspects are implemented with proxies. The limitation of this is that if an object calls a method on itself (which is what's happening here because of inheritance) then the proxy doesn't see the call (because it happens internally within the class, like calling a private method), and can't so anything about it.

Which makes sense but seems to be incredibly dangerous as it fails to write any data without any error message or warning.

Solution 2

there is another way instead of hibernate template( hibernate template will couple spring to hibernate that is why it is deprecated in Spring 3.1 ) the key to solve this issue is to remove any configuration for the hibernate except the dialct and the url in simple way,Remove the transactional stuff from your hibernate properties as You want spring to manage transactions, not hibernate. as Marten Deinum mentioned in this url http://forum.springsource.org/archive/index.php/t-47667.html here is a snippet of my spring xml configuration file

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">    
        <value>
            classpath:/com/spring/hibernate.cfg.xml
        </value>
    </property>       
    </bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

and here is the hibernate file

<session-factory> 
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>

<mapping resource="com/spring/BloodType.hbm.xml" />
</session-factory>

do not forget to write @Transactional in your method or class also use

Session session = sessionFactory.getCurrentSession();

and this

BloodType b = new BloodType();
b.setId(new Long(1));
BloodType b1 = (BloodType)session.get(BloodType.class, 12L);
session.delete(b1);
session.save(b);

would work just fine without any need for session.flush() nor transaction.commit() hope it works

Solution 3

using hibernate template solves it

@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
       hibernateTemplate = new HibernateTemplate(sessionFactory);
}

and then use the template like in this link http://singgihpraditya.wordpress.com/2010/02/13/spring-3-0-and-hibernate-tutorial-part-1/

your reply would be great to share

Share:
13,717
Danack
Author by

Danack

Coder, photographer, cake baker. My stuff you may be interested in: Console - A fork of the Symfony/console to allow it to be used with real DI, instead of commands executing the code. LowMemoryClassloader - A classloader that should be significantly faster than the Composer one, particularly for dynamically generated code. PHP-To-Javascript - Convert PHP to Javascript automatically, because YOLO. FlickrGuzzle - A guzzle based implementation of the Flickr api. Well most of it, the parts people use at least. Auryn - A a pure dependency injector, with a few extra spices. #SOreadytohelp

Updated on June 05, 2022

Comments

  • Danack
    Danack almost 2 years

    I've 'inherited' a project which uses Spring annotations to manage transactions/sessions with Hibernate. Or at least it's meant to be. Currently the Hibernate sessions never get flushed (they are set to FLUSH_MODE_NEVER) and the DAO's need to be flushed by hand for any data to be written to the database.

    Also all the DTO objects stay resident in hibernate's memory, eventually leading to an OutOfMemory error.

    I believe I need to tell Spring/Hibernate to close the session or commit the transaction. In my controller class I have the annotated method for handling the requests:

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ...
        ...
    }
    

    and in the applicationContetxt.xml file I believe I setup the hibernate transaction manager and tell spring to use the annotations:

    <!-- hibernate3 transaction manager -->
    <bean id="transactionManagerLocal" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="dataSource" ref="${local.data.source}" />
        <property name="sessionFactory" ref="localSessionFactory" />
    </bean>
    
    <!-- Demarcate using @Transactional annotation -->
    <tx:annotation-driven transaction-manager="transactionManagerLocal" order="200" />
    

    Not only am I pretty sure that the config is wrong by the way data doesn't get written to the DB without manually calling flush on each of the DAO's, from the log file we can see that transaction manager has it's flushing and session closing disabled:

    INFO  [http-8080-2] TransactionFactoryFactory - Transaction strategy: org.springframework.orm.hibernate3.SpringTransactionFactory
    INFO  [http-8080-2] TransactionManagerLookupFactory - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
    INFO  [http-8080-2] SettingsFactory - Automatic flush during beforeCompletion(): disabled
    INFO  [http-8080-2] SettingsFactory - Automatic session close at end of transaction: disabled
    

    What needs to be done to make Spring/hibernate automatically flush the DAOs and/or close the session to prevent huge amounts of memory being used by Hibernate?

    cheers Dan

    <!-- MySQL/InnoDB session factory -->
    <bean id="localSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="${local.data.source}"/>
        <property name="mappingResources">
            <list>
                <value>net/company/projectname/domain/ExchangeRate.hbm.xml</value>
                <!-- Other  -->
    
            </list>
        </property>
    
       <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
                <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
                <!-- 
                DOES NOTHING
                <prop key="hibernate.transaction.flush_before_completion">true</prop>
                <prop key="hibernate.transaction.auto_close_session">true</prop>
                -->
            </props>
        </property>
    </bean>
    
    <!-- hibernate3 transaction manager -->
    <bean id="transactionManagerLocal" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="dataSource" ref="${local.data.source}" />
        <property name="sessionFactory" ref="localSessionFactory" />
    </bean>
    
    
    <!-- Demarcate using @Transactional annotation -->
    <tx:annotation-driven transaction-manager="transactionManagerLocal" order="200" />
    
    <bean id="exchangeRateDAO" class="net.company.project.dao.hibernate.impl.ExchangeRateDAOImpl">
         <property name="sessionFactory" ref="localSessionFactory"/>
     </bean>