I use hibernate + ehcache to read a workflow engine database.
hibernate does not write anything on that database.
If i set TimetoLive setting in the cache, the cache won't reflect any database changes unless TimetoLive arrives.
database changes is done by the workflow engine API, so there is no way to use hibernate to write the database.
Shouldn't ehcache knows the cache is expired and do the updates for me ?
Any clean way to solve the cache wrong problem ?
the cache won't reflect any database changes unless TimetoLive arrives.
That's the intended functionality! These second level caches do nothing but store data in hash maps and know nothing about the changes unless you tell it to or the time to evict the objects out of cache and reread them.
To solve this is to not use caches on volatile objects.
If i set TimetoLive setting in the cache, the cache won't reflect any database changes unless TimetoLive arrives.
So that means you are not using it.
database changes is done by the workflow engine API, so there is no way to use hibernate to write the database.
So as an laternative (to timetoLive), that means you need cache mode to read-write or read-nonstrictly-write (check the name something like that). If its not reflecting the chnages and I am asssuming two things
Your workflow Engine is using hibernate
And your cache setting is read-only
Related
I have an application using in-memory ignite caches. What I would like to do is, after user input, trigger the persistence of those caches in a Postgres DB.
I already checked the ignite persistence with writeThrough and WriteBehindEnabled properties. it doesn't work in this case because I don't want to write on the db every time I write on the caches.
I also found that, when configuring the caches with persistence, we create the store with a CacheConfiguration<key, value>, we can then use the following to trigger a write :
cache.getSnap(ignite, snapdId).getCache().forEach(e -> {
cache.getConfig().getCacheStoreFactory().create().write(e);
});
Unfortunately this throws an exception with this.session().cacheName() as the session is null.
The this.session() returns the following attribute: #CacheStoreSessionResource private CacheStoreSession ses;
If someone knows how I could do that, that would very much help me.
Thanks !
That's just not how the Cache Store is intended to work. I would suggest either:
Two tables, one writes through to Postgres, the other one is purely in-memory. In this one, you can use the JDBC Cache Store adapter
Write your own Cache Store adapter. In this, you would have an extra column that would indicate whether the row should be written through
The javadocs for CacheStoreMode differentiate in a point I cannot really grasp:
The javadocs for the USE mode:
Insert/update entity data into cache when read from database and when
committed into database: this is the default behavior. Does not force
refresh of already cached items when reading from database.
The javadocs for the REFRESH mode differ in the last sentence:
Forces refresh of cache for items read from database.
When an existing cached entity instance is updated when reading from database, this would typically involve overwriting the existing data. So what is the difference between forcing and not forcing a refresh in this context?
Thank you.
As far as I know:
CacheStoreMode.USE should be used if a given EntityManagerFactory has an exclusive write-access to the underlying database thus it implies that there is no chance for an entity instance stored in the shared cache to be stale.
CacheStoreMode.REFRESH should be enabled if the underlying database might be accessed by multiple commiters (i.e. EntityManagerFactory instances, applications in different JVMs, external JDBC sources) thus an entity instance stored in the shared cache may become stale.
Since CacheStoreMode.USE does not force refresh of already cached entities when reading from the database, CacheStoreMode.REFRESH does.
I think it will make difference where the most recent updated data from the database is needed, where it gets updated from the back-end, not through the application.
In my application, its the same case (but not using any cache strategy), where we have to load all data each time; as it gets modified implicitly through messaging from the external system, else we will be dealing with the stale data.
There might be few cases where scheduled jobs, external systems etc. update database directly there CacheStoreMode.REFRESH is appropriate; while for normal case CacheStoreMode.USE.
[Other than this I can't recollect any other cases, where it might make difference between these two modes]
Edit: The documentation seems confusing & too short to explain properly. Also, in case of native queries, bulk updates etc. items are skipped & aren't cached.
CacheStoreMode.USE: Only new items are put into the cache, not for already cached ones.
CacheStoreMode.REFRESH: New items are put into the cache & already existing cached items are refreshed.
I am trying to understand how JPA works. From what I know, if you persist an Entity, that object will remain in the memory until the application is closed. This means, that when I look for a previously persisted entity, there will be no query made on the database. Assuming that no insert, update or delete is made, if the application runs long enough, all the information in it might become persistent. Does this mean that at some point, I will no longer need the database?
Edit
My problem is not with the database. I am sure that the database can not be modified from outside the application. I am managing transactions by myself, so the data gets stored in the database as soon as I commit. My question is: What happens with the entities after I commit? Are they kept in the memory and act like a cache? If so, how long are they kept there? After I commit a persist, I make a select query. This select should return the object I persisted before. Will that object be brought from memory, or will the application query the database?
Not really. Think about it.
Your application probably isn't the only thing that will use the database. If an entity was persisted once and stored in memory, how can you be sure that, let's say, one hour later, it won't be changed by some other means? If that happens, you will have stale data that can harm logic of your application.
Storing data in memory and hoping that everything will be alright won't bring any benefits. That's why data stored in database is your primary source of information, and you should query it every time, unless you are absolutely sure that a subset of data won't change.
When you persist an entity an entity this will add it to the persistence context which acts like a first level cache (this is in-memory). When the actual persisting happens depends on whether you use container managed transactions or deal with transactions yourself. The entity instance will live in memory as long as the transaction is not commited, and when it is it will be persisted to the database or XML etc.
JPA can't work with only the persistence context (L1 cache) or the explicit cache (L2 cache). It always needs to be combined with a datasource, and this datasource typically points to a database that persists to stable storage.
So, the entity is in memory only as long as the transaction (which is required for JPA persist operations) isn't committed. After that it's send to the datasource.
If the transaction manager is transaction scoped (the 'normal' case) then the L1 cache (the persistence context) is closed and the entities do not longer exist there. If the L1 cache somehow bothers you, you can manage it a bit explicitly. There are operations to clear it and you could separate your read operations (which don't need transactions) from write operations. If there's no transaction active when reading, there's no persistence context, an entity becomes never attached and is thus never put into this L1 cache.
The L2 cache however is not cleared when the transaction commits and entities inside it remain available for the entire application. This L2 cache must be explicitly configured and you as an application developer must indicate which entities should be cached in it. Via vendor specific mechanisms (e.g. JBoss Cache, Infinispan) you can put a max on the number of entities being cached and set/define so-called eviction policies.
Of course, nothing prevents you from letting the datasource point to an in-memmory embedded DB, but this is outside the knowledge of JPA.
Persistence means in short terms: you can shut down your app, and the data is not lost.
To achieve that you need a database or some sort of saving data in a way that it's not lost when you shut down the app.
To "persist" an entity means to actually save it in the data base. Sure, JPA maintains some entity information in memory in the persistence context (and this is highly dependent on configuration and programming practices), but at certain point information will be stored in the data base - for instance, when a transaction commits, or likely (but not necessarily) after flush() or merge() operations.
If you want to keep your entities after committing and for a select query, you need to use the query cache. Just Google around on that term and it should be clear to you.
I have a scenario where I am displaying the data in the database which changes frequently (changed by outside application) on a webpage using Spring MVC, somewhat similar to a stock monitoring application. Currently i am using a daemon thread which fires on web container startup and queries the database every 45 secs and stores the data in the application wide hashmap object. And the web application reads the data from hashmap (instead of database) for displaying the data.
I have read about third party caching API's like Ehcache and OSCache. I have read the documentation on Ehcache and seems like I can use the Hibernate query caching technique instead of a daemon thread.
Now my query if I use hibernate and enable query caching and set timetoidle to 45 secs will the data in the cache is automatically refreshed to reflect latest data in the database or do i need force refresh (query the database again and repopulate the cache) the cache, also can you explain what a self populating cache is.
In the Ehcache docs a SelfPopulatingCacheis described as a:
A selfpopulating decorator for Ehcache that creates entries on demand.
That means when asking the SelfPopulatingCache for a value and that value is not in the cache, it will create this value for you. This blog article gives a lot of details and also code (inclusively auto-updating).
For me, it sounds that a Ehcache SelfPopulatingCache is what would fit your needs best. So I'd recommend to have a closer look at.
A Hibernate 2nd level cache would surely help to increase system performance, but not solve your problem, as I understand it. It's true when using Ehcache and setting timeToIdleSeconds the cache expires after that time, but it's not refreshed automatically.
Take a look at what Hibernate docs write about query cache:
The query cache does not cache the state of the actual entities in the cache; it caches only identifier values and results of value type. For this reason, the query cache should always be used in conjunction with the second-level cache for those entities expected to be cached as part of a query result cache (just as with collection caching).
Finally, OSCache is outdated.
I'm creating a service that has read-only access to the database. I have a query cache and a second level cache enabled (READ_ONLY mode) in Hibernate to speed up the service, as the tables being accessed change rarely.
My question is, if someone goes into the DB and changes the tables manually (i.e. outside of Hibernate), does the cache recognize automatically that it needs to be cleared? Is there a time limit on the cache?
Nope, the cache isn't going to scan the database for you to magically update itself when the underlying data changes. Changes that do not come through the L2 cache will not appear in it. How long it takes to time out etc. depends on your provider and whatever the default settings are. It looks like the default ehcache.xml is for 2 minutes.
If you don't go through Hibernate APIs to make your changes, the second-level-cache won't get notified and the changes won't be visible. The usual way to deal with this situation is to evict the corresponding objects from the second-level-cache programatically to force a refresh. The SessionFactory provides methods allowing to do this. From the section 19.3. Managing the caches of the documentation:
For the second-level cache, there are
methods defined on SessionFactory
for evicting the cached state of an
instance, entire class, collection
instance or entire collection role.
sessionFactory.evict(Cat.class, catId); //evict a particular Cat
sessionFactory.evict(Cat.class); //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular
//collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections