ibatis / mybatis caching within a restful webservice - jersey

I am using mybatis within a Jax-RS (Jersey) restful web app. So automatically, I dont have a session or state management.
Question is how can I use the caching features of mybatis ?

Caching in MyBatis is very straight forward. Per the documentation (pg 42 of the user manual http://mybatis.googlecode.com/svn/trunk/doc/en/MyBatis-3-User-Guide.pdf)
By default, there is no caching enabled, except for local session caching, which improves performance and is required to resolve circular dependencies. To enable a second level of caching, you simply need to add one line to your SQL Mapping file:
MyBatis 3 - User Guide
6 June 2011 43
<cache/>
Literally that’s it.
The common pitfalls I had while doing this:
On the mapper you add the cache element to; if you have dependent entities, make sure to explicitly flush the cache when required. Even though flushing is already done for you on insert, update, delete for the elements in the mappings you have set the cache element, sometimes you have to flush a cache due to updates/deletes/etc defined in different xml mappings.
Basically, when you're thinking about your caching, you should ask yourself, "When this entity is changed, do I want it to flush a cache for an entity in a different mapping?" If the answer is yes, use cache-ref element as opposed to just cache.
Ex from page 45 of the doc:
<cache-ref namespace=”com.someone.application.data.SomeMapper”/>

Related

Spring Cache to Disable Cache by cacheName configuration

I am using spring boot, and it's very easy to integrate spring cache with other cache component.
By caching data, we can use #Cachable annotation, but still we need configure and add cacheName to the cacheManager, without this step, we will get an exception while accessing the method:
java.lang.IllegalArgumentException: Cannot find cache named 'xxxx' for Builder
My question is, is that able to disable the cache instead of raising the error if we not configure the cacheName? I raised this because spring cache provide a configuration spring.cache.cacheNames in CacheProperties.
Not sure if the condition attribute in #Cachable works for this.
Any idea is appreciate!! Thanks in advance!
It really depends on your "caching provider" and the implementation of the CacheManager interface, in particular. Since Spring's Cache Abstraction is just that, an "abstraction" it allows you to plugin different providers and backend data stores to support the caches required by your application (i.e. as determined by Spring's caching annotations, or alternatively, the JSR-107-JCache annotations; see here).
For instance, if you were to use the Spring Framework's provided ConcurrentMapCacheManager implementation (not recommended for production except for really simple UCs), then if you choose to not declare your caches at configuration/initialization time (using the default, no-arg constructor) then the "Caches" are lazily created. However, if you do declare your "Caches" at configuration/initialization time (using the constructor accepting cache name arguments), then if your application uses a cache (e.g. #Cacheable("NonExistingCache")) not explicitly declared, then Exception would be thrown because the getCache(name:String):Cache method would return null and the CacheInterceptor initialization logic would throw an IllegalArgumentException for no Cache available for the caching operation (follow from the CacheIntercepter down, here, here, here, here and then here).
There is no way to disable this initialization check (i.e. throw Exception) for non-existing caches, currently. The best you can do is, like the ConcurrentMapCacheManager implementation, lazily create Caches. However, this heavily depends on your caching provider implementation. Obviously, some cache providers are more sophisticated than others and creating a Cache on the fly (i.e. lazily) is perhaps more expensive and costly, so is not supported by the caching provider, or not recommended.
Still, you could work around this limitation by wrapping any CacheManager implementation (of your choice), and delegate to the underlying implementation for "existing" Caches and "safely" handle "non-existing" Caches by treating it as a Cache miss simply by providing some simple wrapper implementations of the core Spring CacheManager and Cache interfaces.
Here is an example integration test class that demonstrates your current problem. Note the test/assertions for non-existing Caches.
Then, here is an example integration test class that demonstrates how to effectively disable caching for non-existing Caches (not provided by the caching provider). Once again, note the test/assertions for safely accessing non-existing Caches.
This is made possible by the wrapper delegate for CacheManager (which wraps and delegates to an existing caching provider, which in this case is just the ConcurrentMapCacheManager again (see here), but would work for any caching provider supported by Spring Cache Abstraction) along with the NoOpNamedCache implementation of the Spring Cache interface. This no-op Cache instance could be a Singleton and reused for all non-existing Caches if you did not care about the name. But, it would give you a degree of visibility into which "named" Caches are not configured with an actual Cache since this most likely will have an impact on your services (i.e. service methods without caching enabled because the "named" cache does not exist).
Anyway, this may not be one you exactly want, and I would even caution you to take special care if you pushed this to production since (I'd argue) it really ought to fail fast for missing Caches, but this does achieve what you want.
Clearly, it is configurable and you could make it conditional based on cache name or other criteria, in that, if your really don't care or don't want caching on certain service methods in certain contexts, then it is up to you and this approach is flexible and completely give you that choice, if needed.
Hope this gives you some ideas.

Create cache from object type through annotations

So,
I'm trying to convert our existing caching (ehcache) to ignite cache, and migrating to spring annotations. I'm running into some difficulty making the annotations work the same as our existing caches though - our existing caches are created automagically whenever we cache something of a new class, and the new cache has the same name as the object's class.
All the current cache logic (along with most of the normal CRUD operation logic) is in an abstract class that's extended for all our persistent objects. In researching the spring annotations, though, it seems like I need to define the cache name on the method - which obviously doesn't work for the abstract class, unless I want all our objects to be in the same cache (possible but definitely not ideal). Ideally I'd specify the cache name as "#this.class.toString", but SPEL isn't allowed in the cache name, like it is in the key.
It seems like the only way to resolve the cache dynamically is by creating your own cache resolver, but for some reason IgniteCache doesn't extend springframework Cache, but javax Cache, and the cache resolver has to return the former. So I'm not even clear how Ignite cache works with spring annotations at all?
This seems like a pretty straightforward use case to me, so it seems weird that spring annotations force me to provide an explicit name on the method, when I'd assume most applications of any significant size are abstracting their persistence methods, and I feel like I must have missed some crucial documentation, but I sure can't find it. Is there a way to specify the name of the cache on the concrete implementation, but keep the caching annotation on the abstract methods?
Thanks!
Your question is quite dense and it's not very clear what you're trying to do. What is "your existing caching" for a start? You need some way to flag the places where you actually cache things I guess. I assume you already understood you need to put a cache annotation there.
As for automatically creating the cache, I wouldn't switch to a different caching system and trying to implement that. Try to migrate first to the cache annotations with your existing cache infrastructure and then migrate to ignite.
Let's pretend you do both still. You are right CacheResolver is the way to go and it can adapt to either a regular org.springframework.cache.Cache or a javax.cache.Cache. Once you have a setup that works, I'd do the following:
In your CacheResolver implementation, inject the cache manager that has been configured
Based on the method call, figure out the cache name to use (get the return type of the method, extract the FQN)
Check if the cache manager has such cache. If it does, return that. If it doesn't create a new cache and add it and then return that
If you're using JCacheCacheManager, you can invoke addCache to create a new cache and then wrap the result in JCacheCache to comply with the signature of CacheResolver.
Last note: automatically creating the cache based on the FQN seems a bit fragile to me, especially if you have sub-classes. You need a bit of control on the caches you create and the settings you apply to them (expiration, size, etc).

How exactly does one integrate a cache in his project (spring + hibernate)

I have a project that supports 10's of concurrent users.
My project is a spring + hibernate project with a MYSQL DB.
I would like to keep a cache for some of my entities (i.e. Player)
I have a couple of questions:
1) how do I exactly work with a cache (when i have one) ? if i have to persist a Player do i change the cache and immediately persist with hibernate?
2) Does spring support a cache mechanism ? if so how does one work with it?
Hibernate
Hibernate has Second level cache. To start work with you need to:
choose some cache provider (EHCache, Infinispan, ...).
configure cache region (and choose corresponding strategy depending on your situation)
enable cache for some entity
It is declarative, most of the time you do not need to change any application code.
Spring
Spring has cache abstraction. There are some common steps (choose chache provider, configure cache regions). But it is more general pourpose cache, not related to Hibernate entities and transactions. So you must do more work (annotate all necessary methods with annotations).
In general if your Player class is a Hibernate entity then it will be better to go with Hibernate cache. It may be not true if you have some special demands.
Hope it helps.

How do I invalidate a single entry from springmodules method cache?

We are using springmodules method caching (Spring 2.0.7) in combination with ehcache to cache data which is requested often, in order to take load from the database.
E.g. we are caching the method result of public Profile getUserProfile(User u) {...}: when the user updates data in his own profile, it would be nice to invalidate the cached Profile only for this single User directly after the update, so that the changes are reflected in the user interface right away.
Is there a way to achieve this without invalidating the complete cache for this method?
Or is there a better option than springmodules-caching for this use case?
Thanks a lot for any hints.
Or is there a better option than springmodules-caching for this use case?
Use Spring 3.1 has this new cache feature.
How do I invalidate a single entry from springmodules method cache?
By #CacheEvict from Spring 3.1
The Spring Reference for 3.1 has a nice chapter for this: 28.3 Declarative annotation-based caching

Is there a provider agnostic way of getting up to date cache statistics in Spring framework?

Spring provides a useful feature of Cache Abstraction
But what I could not find is a provider agnostic way to get live cache statistics. Essentially I just want to show a list of all the cache names and their corresponding keys with the count of hits, misses, and sizes (in kb) either on a web page or via JMX. I know Ehcache does provide this feature and if I use ehcache API inside the code I can get it (have already used it in the past). But I believe using Ehcache API inside the code takes away the whole notion of the Spring framework's cache abstraction.
The only common, provider-agnostic thing you have is CacheManager interface, which provides the following method:
Collection<String> getCacheNames()
It returns a collection of the caches known by the cache manager.

Resources