-->
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.  [ 4 posts ] 
Author Message
 Post subject: Does Hibernate cache by default?
PostPosted: Tue Jul 18, 2006 4:31 pm 
Newbie

Joined: Tue Jul 18, 2006 2:50 pm
Posts: 3
Hibernate version:
Hibernate 3.2

Mapping documents:
Code:
<?xml version="1.0"?>
[code]<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping >
 
  <class name="src.TickerEntry" table="steamsports.TickerEntry">
    <id name="id" column="id" type="java.lang.Integer">
      <generator class="increment"/>
    </id>
    <property name="league"  />
    <property name="display" />
    <property name="userFavoritesId"  />
  </class>
 
</hibernate-mapping>[/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.url">jdbc:mysql://localhost/</property>
   <property name="connection.username">name</property>
   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
   <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
   <property name="connection.password">pass</property>
    <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    <property name="hibernate.cache.use_query_cache">false</property>
    <property name="hibernate.cache.use_second_level_cache">false</property>
    <property name="hibernate.cache.use_structured_entries">false</property>
    <!--  thread is the short name for
      org.hibernate.context.ThreadLocalSessionContext
      and let Hibernate bind the session automatically to the thread
    -->
    <property name="current_session_context_class">thread</property>
    <!-- this will show us all sql statements -->
    <property name="hibernate.show_sql">true</property>

   <!-- mapping files -->
   <mapping resource="src/TickerEntry.hbm.xml" />

</session-factory>
</hibernate-configuration>


Code between sessionFactory.openSession() and session.close():
Code:
public class HibernateMainApp
{
    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getHibernateSession();
        TickerEntryNonHibernate noHibernate = new TickerEntryNonHibernate();
       
        TickerEntry one = (TickerEntry) session.load(TickerEntry.class, new Integer(1));
        System.out.println("One: " + one);
       
        noHibernate.performSelect();
        noHibernate.performUpdate();
        noHibernate.performSelect();

        TickerEntry two = (TickerEntry) session.load(TickerEntry.class, new Integer(1));
        System.out.println("Two: " + two); 

        session.close();
        HibernateSessionFactory.sessionFactory.close();           
    }


-----

Code:
public class HibernateSessionFactory
{
    public static final SessionFactory sessionFactory;
   
    static {
        try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            System.err.println("Fail to initialize session factory!");
            throw new ExceptionInInitializerError(ex);
        }
    }
   
    public static Session getHibernateSession() throws HibernateException {
        return sessionFactory.openSession();
    }   
}


----
Code:
public class TickerEntryNonHibernate
{
    private Connection conn;
   
    public TickerEntryNonHibernate() {
        try {
            String username = "name";
            String password = "pass";
            String url = "jdbc:mysql://localhost";
           
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            conn = DriverManager.getConnection(url, username, password);
            System.out.println("Database successfully connected");
        }
        catch (Exception e) {
            System.err.println("Cannot connect to database");
        }
    }
   
   
    public void performSelect() {
        if ( conn != null ) {
           
            ResultSet results = null;
            Statement statement = null;
           
            try {
                statement = conn.createStatement();
                String sql = "SELECT * FROM TickerEntry";                 
                statement.executeQuery(sql);
                results = statement.getResultSet();
               
                while ( results.next() ) {
                    System.out.println(results.getInt("id") + "    " + results.getString("Display") + "    " + results.getInt("UserFavoritesID") + "    " + results.getString("League"));                   
                }
               
                results.close();
                statement.close();             
            }
            catch (SQLException sqle) {
                System.err.println("Error executing select statement");
            }
            finally {
            }
        }
        else {
            System.out.println("Not connected to databse...");
        }
    }
   
    public void performUpdate() {
        if ( conn != null ) {
           
            ResultSet results = null;
            Statement statement = null;
           
            try {               
                statement = conn.createStatement();               
                String sql = "UPDATE TickerEntry SET League = 'Update from JDBC' WHERE ID = '1'";                 
                statement.executeUpdate(sql);
               
                statement.close(); 
               
            }
            catch (SQLException sqle) {
                System.err.println("Error executing select statement");
            }
            finally {
            }
        }
        else {
            System.out.println("Not connected to databse...");
        }
    }
   
    public void resetData() {
        if ( conn != null ) {
           
            ResultSet results = null;
            Statement statement = null;
           
            try {
                statement = conn.createStatement();
                String sql = "UPDATE TickerEntry SET League = 'RESET!!' WHERE ID = '1'";                 
                statement.executeUpdate(sql);
               
                statement.close();
                Thread.sleep(1000 * 5);
            }
            catch (SQLException sqle) {
                System.err.println("Error executing select statement");
            }
            catch (Exception e) {
                System.err.println("Sleeping problems...");
            }
            finally {
               
            }
        }
        else {
            System.out.println("Not connected to databse...");
        }
    }

}




Full stack trace of any exception that occurs:

Name and version of the database you are using:
mysql Ver 14.7 Distrib 4.1.11, for pc-linux-gnu (i386)

The generated SQL (show_sql=true):
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Database successfully connected
Hibernate: select tickerentr0_.id as id0_0_, tickerentr0_.league as league0_0_, tickerentr0_.display as display0_0_, tickerentr0_.userFavoritesId as userFavo4_0_0_ from steamsports.TickerEntry tickerentr0_ where tickerentr0_.id=?
One: 1, RESET!!, A, 223
1 A 223 RESET!!
2 A 223 Baseball
1 A 223 Update from JDBC
2 A 223 Baseball
Two: 1, RESET!!, A, 223

Debug level Hibernate log excerpt:


Basically, I wanted to test if Hibernate does caching by default. I created a simple example where I have Hibernate to retrieve a row. Then I used JDBC (or manually) to update that row in the database. Then finally, ask Hibernate to retrieve that row again. My assumption is that it should pick up the updated values for that row, but in fact it some how got back the old value (or cache). Looking at the output, looks like Hibernate only hit the database the first time, but not the second time.

I've tried many things from using get() instead of load(), used LockMode, CacheMode, flush(), evict().

Does any one have any clue why it behaves this way?

Thanks![quote][/quote]
Code:


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 18, 2006 6:01 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Hibernate's session cache stores the entity when it is first loaded. Evicting the entity should cause it to be reloaded the second time load is called. If that's not happening then you must be inside a transaction, so the connection's view of the DB is stale. If you change your connection mode to autocommit (not recommended), or commit (or rollback) your transaction before the second hibernate load, you'll get the "current" view of the DB, rather than the transaction's view.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 18, 2006 6:36 pm 
Newbie

Joined: Tue Jul 18, 2006 2:50 pm
Posts: 3
Yes it works great with autocommit = true OR autocommit = false and start a transaction with begin() and commit(). But could you tell me why autocommit is not recommended?

Is it because autocommit defeats the purpose of cache in Hibernate? So if autocommit is set to true, then each query will always hit the database no matter what. Is this a reason for not recommending autocommit?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 18, 2006 7:27 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
No, that's not the reason. It's because you can get surprizing results, especially if you're using the default flush mode (auto). You can make a few changes to a persistent object, intending to throw it away (say, you load it, change a field to make it more user-friendly, generate some output for the user, then discard the object), but those changes might get saved to the DB because the session cache is flushed to the DB every time you query something. And because you're in autocommit mode, you won't have bothered to start a transaction (and that's also a bad idea), so there's nothing to roll back to undo your accidental DB write.

There are other reasons, but I think that one should convince you that using autocommit can lead to bugs that can be impossible to track down.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.