Results 1 to 9 of 9

Thread: Hibernate Caching problem

  1. #1

    Default 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. #2
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    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.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  3. #3

    Default

    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");
        }
    	
    }

  4. #4
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Quote 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
    This post can contain insufficient information.

  5. #5

    Default

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

  6. #6
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    How are you managing the Hibernate Sessions? Are you creating them or are you using Spring transactions etc......?
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  7. #7
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Quote 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
    This post can contain insufficient information.

  8. #8

    Default

    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?

  9. #9
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Quote 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.

    Quote 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
    This post can contain insufficient information.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •