I have an application where I get the data from database (using hibernate).
I want to load the cache (per user) with database state once per day and use the cache instead.
I'm using Spring framework with Hibernate and I know that both of them have some caching possibilities.
What are the differences between them? What would be a better choice?
Starting with Hibernate cache is a more prudent decision in my view, especially because the two don't exclude each other. In terms of performance Spring cache can offer you more, its much higher in the stack, you can cache business results (basically more than you can with hibernate's second level cache).
However one outstanding distinction is clearing the cache. With Spring cache you need to clear explicitly, while the hibernate cache is maintained automatically if your inserts, updates and deletions go through hibernate's framework.
In the context of the projects that I'm involved, using hibernate's second level cache is assumed, a default almost. Spring cache we use for the data that are much more static in nature.
Hibernate has 2 levels of cache. 1. First level 2. Second level
Second level chache is for the whole application and first level cache is for the current hibernate session. There is no cache available per user basis.
Also if you are using spring managed beans + caching. There is a provision for you to cache the beans for entire application rather than for a user. (little uncertain on this)
It sounds to me that you want to store the data in the user's session. ie., as long as the user is having an active session. Spring has a session scoped beans you may want to use these to cache the data per user.
Related
I want to get the details of entries in my custom cache after caching data or eviction of data.
I tried using actuator dependency to get 'actuator/metrics' path to get details but I'm getting empty tomcat server cache. There is no sign of my custom cache say myCache (the name which I passed into #Cacheable annotation value argument).
You tagged your question with Caffeine and Spring Boot, so I assume you use those two products.
If you use a recent Spring Boot and Caffeine, statistics will be automatically available at actuator/caches. If not, double check you have the needed libraries on your classpath and no configuration that enables another cache or disables caching at all, like spring.cache.type=none.
If you don't use Spring Boot, but just Spring, you need to add a CacheManager to your configuration, otherwise Spring defaults to the ConcurrentHashMap which does not have cache statistics.
I have two context on single tomcat pointing to same database. I am using ehcache for 2nd level caching with Hibernate.
Now, when I do any create/update/delete operation on database, it reflect in contect1 cache but to update in contecxt2 cache, it took almost 15-20 min. I can't use refresh/clear function in context2 as I don't know when to refresh.
How Can I refresh context2's Hibernate cache when there is any update happened through context1?
Also to do clustering for Hibernate cache, I need to give IP address and port number, but in my case, both are same for two contexts. So I think I can't use Hibernate cache clustering.
Scenario: Project consists of reference data which is updated once a week. Hence constantly querying this reference data for every transaction from the database is not efficient. Hence the motivation to cache this data.
Question: If secondary level caching and query caching in Hibernate is activated and the cache element in the hibernate configuration is set to read-only, how will hibernate know when to update the cache if a change is made to the database via another program. Is this automatically handled by Hibernate or do we have to clear the cache using some trigger?
If this is handled by Hibernate could someone shed light on how this is handled?
The JBoss documentation was not very clear about the management of the cache.
I am currently using Hibernate 3.6 with Spring 3.1 and do not wish to upgrade to Hibernate 4 if its not necessary.
It wont.
The second level cache expects all access to the data to happen via the ORM framework so if you have another actor in the db your cache will become stale.
You can clear the cache though - see this
code snippet
So you could expose a service that allows the 3rd party to clear the cache on your app when the database gets updated.
I'm writing a web app that supports multiple users. Each user has their own database - using H2. all database schemas are the same.
I wish to use Spring + Hibernate for this application.
So I'm stuck at how to associate a user's database with that user - maybe associated it in the HTTPSession, and extend spring's AbstractRoutingDataSource? but wouldn't this effect Hibernate's cache? Another way is to have a SessionFactory with each datasource, even though every datasource's schema is the same... so I see that as a waste.
Anyways selecting the datasource needs to be dynamic - they can't be pre-configured in context files, as each new user will have its own database created. Is there any existing frameworks/solutions?
I don't know too much about Hibernate Shards, maybe that works?
I might be wrong about the (strict) need to have one SessionFactory per database, as suggested by some resources:
Dynamic DataSource Routing
I'll take some time to re-read everything tomorrow (I didn't get all the details to be honest) and to fully understand the implications of such a setup (although it seems clear that it will break the second-level cache). I'll come back on this later.
I'm writing a web app that supports multiple users. Each user has their own database - using H2. all database schemas are the same.
I wonder how this will scale... How many users do you have? How do you run H2, what mode?
So I'm stuck at how to associate a user's database with that user - maybe associated it in the HTTPSession, and extend spring's AbstractRoutingDataSource?
You'll have to build a SessionFactory per user and associate it to the logged user (in a Map, using the login as key) and then obtain a Session from a given SessionFactory. Binding the lifecycle of the SessionFactory to the HTTP session seems to be a good idea (to save some memory) but I am not sure Spring will be very helpful here. I might be wrong but a variation of the HibernateUtil class and a fully programmatic approach looks easier. I'm not sure you'll need multiple connections per user by the way.
but wouldn't this effect Hibernate's cache?
What cache?
Another way is to have a SessionFactory with each datasource, even though every datasource's schema is the same... so I see that as a waste.
Oh, it's a waste, but that's what you want to do (one database per user). And you don't have the choice (you need one SessionFactory per datadabase). Why do you need one database per user actually? Are you sure this is a wise decision? As already hinted, this means much troubles, won't scale well, adds complexity, etc. Why not using a single database and associating data to the user?
Anyways selecting the datasource needs to be dynamic - they can't be pre-configured in context files, as each new user will have its own database created. Is there any existing frameworks/solutions?
Not to my knowledge. Which is also why I think you'll have to do everything programatically.
I don't know too much about Hibernate Shards, maybe that works?
Given the dynamic needs of your application, I don't see how it could help.
This may help you:
Dynamic Datasource via Spring using HotSwappableTargetSource
Hibernate + Spring using multiple datasources?
Thanks to the help from the 2 people (Pascal and org.life.java)!
It is possible, but with some problems: e.g. the hibernate 2nd level cache/query cache.
This link supplied by Pascal is a very good resource:
http://www.jroller.com/kenwdelong/entry/horizontal_database_partitioning_with_spring.
My main motivation for giving each user a separate database is because the data is likely to grow rapidly, thus horizontal partitioning is required.
I'm using Hibernate second level cache in my application, for certain business reason I can't change the entity annotation any more.
In my project, apart from changing the Database from Hibernate, there exist also other native SQL that do not go through Hibernate. Therefore, the Hibernate second-level cache data could be stale after database being updated from native SQL. That's why I want to disable the second-level cache for certain entities (programmatically or other way than changing annotation).
Thanks in advance!
WARNING: As Jens Schauder noted, it is impossible to configure Ehcache to store 0 elements in memory by setting maxElementsInMemory="0" as it effectively causes opposite effect - sets unlimited size for the cache. This behaviour is not mentioned on the Hibernate Caching page but is documented on Cache Configuration page.
I have quickly reviewed the documentation and haven't found alternative approach yet. I am unable to delete this answer by myself. :-(
My original suggestion:
You can configure the implementation provider of second level cache to short TTL times and/or to store 0 entries of particular entity type.
E.g. if you are using the Ehcache, you can configure it in ehcache.xml:*
<cache
name="com.problematic.cache.EntityName"
maxElementsInMemory="0" <<== this should effectively disable caching for EntityName
overflowToDisk="false" <<== Do not overflow any entries to disk
/>
See Hibernate Caching in Ehcache documentation.
In Terracotta 3.1 and above, you can enable/disable Hibernate 2nd Level Caches on a per region basis, both in the configuration (statically) and at runtime, using the Terracotta Developer Console.
You can also monitor in realtime statistics about the cache and Hibernate, for individual nodes in a cluster or cluster-wide.
Terracotta is open source. For more details, check out Terracotta for Hibernate.