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;
}
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.
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.
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.
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
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
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
.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With