Announcement Announcement Module
Collapse
No announcement yet.
Hibernate Caching problem Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hibernate Caching problem

    Hi,

    I'm using Spring 2.0.3 with Hibernate 3.2.2.ga in a webapp.
    I encoutered the following problem:
    I have a form with a text field wich represents a database table entry.
    When I remove the value from this text field, a spring validator prevents the application to insert an empty value.
    But now this empty value is in the session and is also shown in the application.
    For testing purposes I have set the hibernate flush mode to manual.

    After reloading my pages a couple of times the correct value is shown.
    Is there a way to prevent caching from hibernate or spring?

    I've tried to set some meta tags to my jsp's to prevent the browser from caching
    Code:
      <meta http-equiv="expires" content="now" />
      <meta http-equiv="pragma" content="no-cache" />
      <meta http-equiv="Cache-Control" content="no-cache" />
    but that shouldn't be the problem, beacuse the wrong value is also shown on pages, wich where not loaded before.

    on my hibernate.cfg.xml, I have got the following CacheProvider
    Code:
      <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    thanks in advance.

  • #2
    Presumably when you refresh the page it refetches the object. If you aren't using caching, I'm not sure why you'd have stale data. It would be useful to review the logs and also ensure you are re-fetching.

    Comment


    • #3
      I steped a little bit deeper into my problem.
      Each time a load an object, it will be saved into the hibernate session.
      Now, when I change an attribute to an empty value, the object is not valid any more.
      The spring validator throws an error und shows my error page, but the object is written wrong to the session (with the empty attribute).
      Going to an other navigation point in my app without saving the form, the session says the object is dirty and wants to write it to my database.

      Is there a way, to remove the wrong object from the session, if the validator says it is wrong?
      I allready tried the session.evict() method and it works.
      But I can't imagine that I have to evict all objects from the session if I want to validate them.


      the info statements show the session.getStatistics().getEntityKeys(), my CacheMode and my session dirty state. The rest is the hibernate debug output.
      I try to change a appellation object.
      Code:
      DEBUG [btpool0-1] (ConnectionManager.java:439) - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.Appellation
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.Appellation
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.User
       INFO [btpool0-1] (HibernateUtil.java:63) - IGNORE
       INFO [btpool0-1] (HibernateUtil.java:64) - DIRTY?: false
      DEBUG [btpool0-1] (JDBCTransaction.java:54) - begin
      DEBUG [btpool0-1] (ConnectionManager.java:419) - opening JDBC connection
      DEBUG [btpool0-1] (JDBCTransaction.java:59) - current autocommit status: false
      DEBUG [btpool0-1] (JDBCContext.java:210) - after transaction begin
      DEBUG [btpool0-1] (AbstractBatcher.java:358) - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
      DEBUG [btpool0-1] (AbstractBatcher.java:393) - select this_.appellationId as appellat1_39_0_, this_.appellation as appellat2_39_0_, this_.active as active39_0_ from Appellation this_ where this_.appellationId=
      ?
      Hibernate: select this_.appellationId as appellat1_39_0_, this_.appellation as appellat2_39_0_, this_.active as active39_0_ from Appellation this_ where this_.appellationId=?
      DEBUG [btpool0-1] (AbstractBatcher.java:476) - preparing statement
      DEBUG [btpool0-1] (NullableType.java:133) - binding '1' to parameter: 1
      DEBUG [btpool0-1] (AbstractBatcher.java:374) - about to open ResultSet (open ResultSets: 0, globally: 0)
      DEBUG [btpool0-1] (NullableType.java:172) - returning '1' as column: appellat1_39_0_
      DEBUG [btpool0-1] (AbstractBatcher.java:381) - about to close ResultSet (open ResultSets: 1, globally: 1)
      DEBUG [btpool0-1] (AbstractBatcher.java:366) - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
      DEBUG [btpool0-1] (AbstractBatcher.java:525) - closing statement
      DEBUG [btpool0-1] (JDBCTransaction.java:103) - commit
      DEBUG [btpool0-1] (JDBCContext.java:201) - before transaction completion
      DEBUG [btpool0-1] (JDBCTransaction.java:116) - committed JDBC Connection
      DEBUG [btpool0-1] (JDBCContext.java:215) - after transaction completion
      DEBUG [btpool0-1] (ConnectionManager.java:402) - aggressively releasing JDBC connection
      DEBUG [btpool0-1] (ConnectionManager.java:439) - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.Appellation
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.Appellation
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.State
       INFO [btpool0-1] (HibernateUtil.java:60) - net.bobo.app.model.User
       INFO [btpool0-1] (HibernateUtil.java:63) - IGNORE
       INFO [btpool0-1] (HibernateUtil.java:64) - DIRTY?: true

      my appellation object mapping.
      Code:
      <?xml version="1.0"?>
      <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
      <hibernate-mapping>
          <class name="net.bobo.app.model.Appellation" table="Appellation">
              <comment></comment>
              <id name="appellationId" type="int">
                  <column name="appellationId" />
                  <generator class="increment" />
              </id>
              <property name="appellation" type="string">
                  <column name="appellation" not-null="true">
                      <comment></comment>
                  </column>
              </property>
              <property name="active" type="boolean">
                  <column name="active" not-null="true">
                      <comment></comment>
                  </column>
              </property>
          </class>
      </hibernate-mapping>
      appellation manager
      Code:
      public class AppellationManager {
      	public void saveAppellation (Appellation appellation) {
      		Session session = HibernateUtil.getSession();
      		session.beginTransaction();
      		try {
      			session.saveOrUpdate(appellation);
      			session.getTransaction().commit();
      		} catch (HibernateException e) {
      			session.getTransaction().rollback();
      			throw e;
      		}
      	}
      	
      	public Appellation getAppellation(int appellationId) {
      		Appellation app = null;
      		Session session = HibernateUtil.getSession();
      		session.beginTransaction();
      		//session.setFlushMode(FlushMode.MANUAL);
      		try {
      			Criteria crit = session.createCriteria(Appellation.class);
      			crit.add(Restrictions.eq("appellationId", appellationId));
      			app = (Appellation)crit.uniqueResult();
            //session.evict(app);
      			session.getTransaction().commit();
      		} catch (HibernateException e) {
      			session.getTransaction().rollback();
      			throw e;
      		}
      		return app;
      	}
        ...
      }
      my appellation validator
      Code:
      public class AppellationEditValidator implements org.springframework.validation.Validator {
      	public boolean supports(Class clazz)
          {
              return Appellation.class.isAssignableFrom(clazz);
          }
      
          /**
           * Validates an Appellation command object. Ensures that the name of
           * the appellation is not empty.
           * @see Appellation 
           */
          public void validate(Object command, Errors errors)
          {
          	Appellation appellation = (Appellation) command;
              if (appellation == null) return;
          	ValidationUtils.rejectIfEmptyOrWhitespace(errors, "appellation", "appellation.name", "error.empty.value");
          }
      	
      }

      Comment


      • #4
        Originally posted by builderdash View Post
        Each time a load an object, it will be saved into the hibernate session.
        Now, when I change an attribute to an empty value, the object is not valid any more.
        The spring validator throws an error und shows my error page, but the object is written wrong to the session (with the empty attribute).
        Going to an other navigation point in my app without saving the form, the session says the object is dirty and wants to write it to my database.
        Shouldn't you have a new session for each requests?

        Joerg

        Comment


        • #5
          How can I have a new session per request?
          Can you give my some clues?

          Comment


          • #6
            How are you managing the Hibernate Sessions? Are you creating them or are you using Spring transactions etc......?

            Comment


            • #7
              Originally posted by builderdash View Post
              How can I have a new session per request?
              This is more or less the default behavior in web applications, e.g. when using OSIV (a session spans exactly a request) or JTA (a session spans a transaction). Since you seem to manage the sessions yourself I don't know what exactly happens in your case. There is a section "Contextual Sessions" in the Hibernate reference about session management. Also have a look at the configuration properties, especially those that link to "Contextual Sessions".

              Joerg

              Comment


              • #8
                Thanks for the help.

                How are you managing the Hibernate Sessions? Are you creating them or are you using Spring transactions etc......?
                I used a own written HibernateUtil Class to manage my session
                Code:
                public class HibernateUtil {
                	private static final SessionFactory sessionFactory;
                	private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
                	private static final ThreadLocal<Transaction> threadTransaction = new ThreadLocal<Transaction>();
                //	private static final Log logger = LogFactory.getLog(HibernateUtil.class);
                	
                	static {
                		try {
                			Configuration cfg = new Configuration();
                			sessionFactory = cfg.configure().buildSessionFactory();
                		} catch (Throwable ex) {
                			ex.printStackTrace(System.out);
                			throw new ExceptionInInitializerError(ex);
                		}
                	}
                	
                	public static SessionFactory getSessionFactory() {
                		return sessionFactory;
                	}
                
                	public static Session getSession() {
                		Session s = (Session) threadSession.get();
                		// Open a new Session, if this thread has none yet
                		try {
                			if (s == null) {
                				s = sessionFactory.openSession();
                				s.setFlushMode(FlushMode.COMMIT);
                				threadSession.set(s);
                			}
                		} catch (HibernateException ex) {
                			throw ex;
                		}
                		return s;
                	}
                
                	public static void closeSession() {
                		try {
                			Session s = (Session) threadSession.get();
                			threadSession.set(null);
                			if (s != null && s.isOpen())
                				s.close();
                		} catch (HibernateException ex) {
                			throw ex;
                		}
                	}
                
                	public static void beginTransaction() {
                		Transaction tx = (Transaction) threadTransaction.get();
                		try {
                			if (tx == null) {
                				tx = getSession().beginTransaction();
                				threadTransaction.set(tx);
                			} 
                		} catch (HibernateException ex) {
                			throw ex;
                		}
                	}
                
                	public static void commitTransaction() {
                		Transaction tx = (Transaction) threadTransaction.get();
                		try {
                			if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack())
                				tx.commit();
                			threadTransaction.set(null);
                		} catch (HibernateException ex) {
                			rollbackTransaction();
                			throw ex;
                		}
                	}
                
                	public static void rollbackTransaction() {
                		Transaction tx = (Transaction) threadTransaction.get();
                		try {
                			threadTransaction.set(null);
                			if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
                				tx.rollback();
                			}
                		} catch (HibernateException ex) {
                			throw ex;
                		} finally {
                			closeSession();
                		}
                	}
                	
                }
                At the moment I try to refactor my application to use the HibernateDaoSupport and Spring transactions. Maybe that old Class was the reason for my problems.

                As Hibernate Session Context, I use
                Code:
                <property name="current_session_context_class">thread</property>
                in my hibernate.cfg.xml.

                Is this the right step?

                Comment


                • #9
                  Originally posted by builderdash View Post
                  At the moment I try to refactor my application to use the HibernateDaoSupport and Spring transactions.
                  You can use the Hibernate API directly, no need for HibernateDaoSupport/HibernateTemplate.

                  Originally posted by builderdash View Post
                  As Hibernate Session Context, I use
                  Code:
                  <property name="current_session_context_class">thread</property>
                  in my hibernate.cfg.xml.
                  Which probably means you have a new session on each request. If ThreadLocals (or any other thread-dependent technology) are used to manage a session (which I assume from the name "thread") the session can not span multiple requests since every requests is executed in a new thread (or just an arbitrary one from a thread pool).

                  Joerg

                  Comment

                  Working...
                  X