Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate reading function shows old data

I've a problem showing data from database. If I update an object, sometimes I get the old data, sometimes the new one. Update function works well (I can see in DB the right update) while the read function seems to get cached data. I've tried to disable both caches, tried to open and close session during update/save, but it's still not working. Both User and Store beans have Lazy fetches. Thanks!

READ FUNCTION:

    public static List<Store> getStoreByUser(User user)
        throws HibernateException {
    List<Store> result = null;
    Session session = sessionFactory.getCurrentSession();   
    Transaction transaction = null;
    try {
        transaction = session.getTransaction();
        Criteria criteria = session.createCriteria(Store.class);
        criteria.add(Restrictions.eq("userUserID", user));
        result = criteria.list();
    } catch (HibernateException he) {
        logger.error("No Store found for user: = " + user, he);
        throw he;
    }
    return result;
}

UPDATE/SAVE FUNCTION:

    public static Integer insertOrUpdateStore(Store store)
        throws HibernateException {
    Integer id = null;
    Session session = sessionFactory.getCurrentSession();   
    Transaction transaction = null;
    try {
                    transaction = session.getTransaction();
        if (store.getStoreID() != null && store.getStoreID() != 0) {

            session.merge(store);
            transaction.commit();

        } else {
                id = (Integer) session.save(store);
            transaction.commit();               
        }
    } catch (HibernateException he) {
        if (transaction != null) {
            transaction.rollback();
        }
    } finally {
    }       
    return id;
}
like image 535
Gore Avatar asked Aug 20 '12 09:08

Gore


People also ask

Which database is used in hibernate?

In the below hibernate example we are using the MYSQL database. you can use any database you just need to update the configuration to change the database connection. Yes, To read the data we must have to insert the data into the database, here is a separate example to insert data into hibernate.

How to map a read-only view in hibernate?

As long as you follow the default naming strategy, you just need a class with an @Entity annotation and an attribute for each database column. You can map a read-only view in the same way. You just need an additional annotation to tell Hibernate that it should ignore the entity for all write operations.

How does hibernate call a function from a SQL statement?

As you can see in the log messages, Hibernate uses the parameters provided to the function function to call the calculate function in the SQL statement. If you want to learn more about JPA’s and Hibernate’s support for custom database function calls, take a look at How to call custom database functions with JPA and Hibernate.

How to insert data into hibernate from MySQL database?

Yes, To read the data we must have to insert the data into the database, here is a separate example to insert data into hibernate. Add dependency for Hibernate and MySQL connector in the project (pom.xml) Create Hibernate configuration file (hibernate.cfg.xml) Configure Session Factory and Session and start the transections


4 Answers

I have the same problem, my query select * returning old data. I have in my hibernate.cfg.xml file turned off 2nd level cache like this

<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>
<property name="hibernate.c3p0.max_statements">0</property>

I'll try add session.flush() or session.clear() before/after transaction.commit() but it not gives positive result

like image 73
mario Avatar answered Oct 07 '22 16:10

mario


You may evict old data so as to ensure that data is fetched from db and not from L1 and L2 caches.

Also you have to make sure your are not in a REPEATABLE_READ isolation level. In this isolation mode, it guarantees that two reads within the same transaction will always return the same result. As the isolation level takes precedence on your cache eviction, the cache evict will not have any visible effect.

There is a ways to work around this behavior: Declare your transaction isolation level to READ_UNCOMMITTED or READ_COMMITTED.

like image 38
user1784833 Avatar answered Oct 07 '22 17:10

user1784833


Usually, you have an isolation level "read committed". This lets your transaction see changes that have been committed by other transaction. The isolation level is implemented by the underlying dbms, not by hibernate.

You can't disable the first level cache (probably by using the stateless session, which shouldn't be used for general purposes). When executing a query, NH always returns values from the cache when it is found there, to ensure that you don't get the same db record more then once in memory.

If this is an issue for you, you should switch to a higher isolation level. For instance repeatable read (which means what it says: when reading the same data several times, you always get the same result). There is still the chance to see changes from other transaction. Using isolation level serializable, you shouldn't have this kind of issue anymore.

Note: switching to another isolation level is a breaking change to most systems and should be planned carefully.

like image 25
Stefan Steinegger Avatar answered Oct 07 '22 18:10

Stefan Steinegger


You can open a new session in order to get "fresh"(updated from database) data without old entities from session cache. In the example below you can see as an entity is being querying from database. Also you can use the same mechanism to return the entity instead of a boolean value, or call session.Refresh() (from your current session of course) to refresh latest changes from database:

        /// <summary>
        ///  Gets an item exists on database.
        /// </summary>
        /// <param name="Id">Item ID to check if exists on database</param>
        /// <returns> True if the <paramref name="Id"/> to check exists on database, otherwise false. </returns>
        public bool Exists<T>(object Id)
        {
            using (var session = NHibernateSessionHelper.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    //get if the item is new. If is new, entity will be null and non exists
                    return session.Get<T>(Id) == null ? false : true;
                    //also you can return the entire table from database, or filter:
                    //session.CreateCriteria<T>().List<T>();
                }
            }
        }

        public void Refresh(object entity)
        {
            //get latest changes from database (other users/sessions changes, manually, etc..) 
            NHibernateSessionHelper.CurrentSession.Refresh(entity);
        }

I hope this helps you.

like image 27
Carlos Avatar answered Oct 07 '22 18:10

Carlos