-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: enable lazy-loading but disable auto-save
PostPosted: Mon Feb 11, 2008 6:28 am 
Newbie

Joined: Mon Feb 11, 2008 5:46 am
Posts: 5
Hello!

While enabling the lazy-loading I have run into the following problem - hibernate automatically saves the persistent object if the one of it's setters is called. I have the impression that hibernate is automatically creating and commiting the transaction (with disabled lazy-loading everything is just fine). If this is true, then I really need to disable this feature.

I am using Hibernate 3.2 with annotations withing spring application.

Also there is an additional thing that I have to mention - I am using mysql replication and in order to make all the sql writes go to master and sql reads go to slave(s), I need to switch between read-only and non read only connection modes, so I have ugly hacks in my code as well.


Hibernate config code:
Code:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>
        <property name="connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</property>
      <property name="connection.datasource">java:/MY_DS</property>
      
      <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
      
      <property name="hibernate.max_fetch_depth">3</property>
      
      <property name="hibernate.connection.release_mode">on_close</property>

        <property name="dialect">cy.axiasoft.webspace.spring.h3.MySQLDialect</property>

        <property name="current_session_context_class">managed</property>

        <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>

              <property name="hibernate.cache.use_query_cache">true</property>

        <property name="show_sql">false</property>

   <!-- mapping list goes here -->
</session-factory>

</hibernate-configuration>


Hibernate config in spring
Code:
<bean id="hibernateSessionFactory" class="foo.h3.SessionFactoryBean">
      <property name="configLocation" value="classpath:hibernate.cfg.xml" />
   </bean>

foo.h3.SessionFactoryBean - this is used for initializing the annotation configuration
Code:
package foo.h3;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;

public class SessionFactoryBean extends LocalSessionFactoryBean {
   
   public SessionFactoryBean() {
      super();      
   }
   
   @Override
   public Configuration newConfiguration(){
      return new AnnotationConfiguration();
   }
}


I have extended spring HibernateTemplate class for switching between read only and non-read only connections
ConfigurableHibernateTemplate:
Code:

package foo.spring.h3;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.context.ManagedSessionContext;
import org.springframework.orm.hibernate3.HibernateTemplate;

/**
* Hibernate template that allows to create read-only or non read-only
* connections
*
* @author armands
*
*/
public class ConfigurableHibernateTemplate extends HibernateTemplate {

   private static final Log log = LogFactory
         .getLog(ConfigurableHibernateTemplate.class);

   private boolean readOnly;

   public ConfigurableHibernateTemplate(SessionFactory sessionFactory,
         boolean readOnly) {
      super(sessionFactory);
      this.readOnly = readOnly;
      setAllowCreate(false);
      setExposeNativeSession(true);
   }

   @Override
   protected Session getSession() {
      final org.hibernate.classic.Session s;
      SessionFactory sessionFactory = getSessionFactory();
      if (!ManagedSessionContext.hasBind(sessionFactory)) {
         s = sessionFactory.openSession();
         s.beginTransaction();
         ManagedSessionContext.bind(s);
      } else {
         s = sessionFactory.getCurrentSession();
      }

      setConnectionModeIfNecessary(s.connection(), readOnly);

      return createSessionProxy(s);
   }

   private void setConnectionModeIfNecessary(Connection connection, boolean ro)
         throws HibernateException {
      try {
         if (connection.isReadOnly() != ro) {
            connection.setReadOnly(ro);
         }
      } catch (SQLException e) {
         throw new HibernateException(e);
      }

   }

   /**
    * The proxy created by this method will ignore close() calls to session
    * object. This is a hack to prevent HibernateTemplate from automatically
    * closing session after executing jdbc calls
    */
   @Override
   protected org.hibernate.classic.Session createSessionProxy(
         final Session session) {

      log.debug("Creating session proxy");
      org.hibernate.classic.Session proxySession = (org.hibernate.classic.Session) Proxy
            .newProxyInstance(Session.class.getClassLoader(),
                  new Class[] { org.hibernate.classic.Session.class },
                  new InvocationHandler() {

                     public Object invoke(Object proxy, Method method,
                           Object[] args) throws Throwable {
                        if (method.getName().equals("close")) {
                           return null;
                        }
                        return method.invoke(session, args);
                     }

                  });
      return proxySession;
   }


   /**
    * Override to always perform flush on non read-only connection
    */
   @Override
   protected void flushIfNecessary(Session session, boolean existingTransaction)
         throws HibernateException {
      try {
         // set connection read-only = false and perform flush if necesary
         session.connection().setReadOnly(false);

         super.flushIfNecessary(session, existingTransaction);
         // restore state
         session.connection().setReadOnly(readOnly);
      } catch (SQLException e) {
         throw new HibernateException("SQL Exception encountered!", e);
      }
   }
}


Code for HttpFilter for transaction commit/rollback
Code:
public class HibernateSessionHandlerFilter implements Filter {

   private Log log = LogFactory.getLog(HibernateSessionHandlerFilter.class);

   private ServiceManager serviceManager;

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      SessionFactoryImplementor hibernateSessionFactory = serviceManager.getHibernateSessionFactory();

      try {
         chain.doFilter(request, response);
         Session session = getCurrentSession(hibernateSessionFactory);

         if (session != null && session.isOpen()) {
            session.getTransaction().commit();

         }
      } finally {
         try {
            Session session = getCurrentSession(hibernateSessionFactory);
            if (session != null && session.isOpen()) {
               // if there still is active and not commited transaction
               // then rollback!
               if (session.getTransaction().isActive()) {
                  try {
                     log.warn("Transaction rollback");
                     session.getTransaction().rollback();
                  } catch (HibernateException ex) {
                     log.warn("Exception while trying to rollback transaction!", ex);
                  }
               }
               session.close();
            }
         } catch (HibernateException he) {
            log.warn("Error while trying to close session!", he);
         }
         ManagedSessionContext.unbind(hibernateSessionFactory);
      }
   }

   public void init(FilterConfig arg0) throws ServletException {
      serviceManager = ServiceManager.getInstance();
   }

   public void destroy() {
   }

   protected Session getCurrentSession(SessionFactory sf) {
      Session s;
      try {
         s = sf.getCurrentSession();
      } catch (HibernateException he) {
         // if exception was thrown then there is no active session
         s = null;
      }
      return s;
   }


Also I was not able to use other transaction factory than JDBCTransactionFactory, because then I got the exception that I cannot change connection mode in managed transaction. I could repeat this exception and post the stack trace if that could help.

Thanks in advance!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 11, 2008 10:35 am 
Newbie

Joined: Mon Feb 11, 2008 5:46 am
Posts: 5
Nevermind, I just realized that I started transaction as soon as I created session, but did not perform commit() after the insert, update or remove operations and thus the commit() was called in filter, when all the uncommited data was sent to db


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.