Add Cache in a class - spring

I have a impl class where I have 2 update methods , method1 is updating complete row in DB whereas method2 is updating only one column in DB of that table.
Now I need to use #Caceable and #CacheEvict here , How can I use in this condition ?

From Spring 3.1 introduces a new feature to allow methods to be cached and evicted thus allowing resource heavy methods to be avoided where possible. Caching is enabled via the new #Cacheable and #CacheEvict annotations.
One example of caching would be, for example, database activity. We can apply the #Cacheable annotation to a find operation and then apply the #CacheEvict to an update / delete operation. In this sense, caching would work much like a second level cache in Hibernate or JPA.
To enable caching on a find method, the method needs to be annotated with the #Cacheable annotation identifying which cache to use. Spring allows multiple caches to be defined each of which can be backed by a different caching abstraction.
#Cacheable("items") //#Cacheable(value = "items", key = "#itemId")
public Item find(long itemId) {
Item item = entityManager.find(Item.class, itemId);
return item;
}
When it is time to invoke the find method, Spring checks in the specified cache to see if the results of the operation have already been cached and if the results can be therefore be returned from cache instead of invoking the method. Spring uses the method arguments as the key, so in this case the itemId parameter.
To evict an entry from the cache when an object is updated in the database, the #CacheEvict annotation can be used. Again, this annotation takes a parameter identifying which cache to use.
#CacheEvict(value = "items", key = "#item.id")
public void updateItem(Item item) {
entityManager.merge(item);
}
EDIT:
#CacheEvict
Used for Cache-removal /cache-cleanup operation. #CacheEvict annotation indicates that a method (or all methods on a class) triggers a cache evict operation, removing specific [or all] items from cache. Various attributes provides complete control to enforce the required behavior for cache-eviction.
for example,
#CacheEvict(value = "products", key = "#product.name")
public void refreshProduct(Product product) {
//This method will remove only this specific product from 'products' cache.
}
#CacheEvict(value = "products", allEntries = true)
public void refreshAllProducts() {
//This method will remove all 'products' from cache, say as a result of flush-all API.
}

Related

Using CachePut and Cacheable

I have two methods as below .One is annotated with #CachePut and another is annotated with #Cacheable.Both of them uses the same key . Based on some of the answers from other posts I figured that #cacheput replaces the value. If that is the case , would the method annotated with #Cacheable be executed for the same id if there is an update to one of the fields in document.
#CachePut(value="testcache",key="#document.id")
public Document update(Document document){
// code to update db
return document
}
#Cacheable(value="testcache")
public Document getDocument(String id){
// query database and fetch document
return document
}
The method annotated with #Cacheable will only be executed if the key has no value in the cache. So, it does not matter whether your #CachePut has updated the document or not. As long as the document is in the cache, getDocument(id) would not go to database. (CachePut does the db & cache update for you)

Spring boot cache evict not working from another thread

I can't understand why cache evict is not working in my scenario. I have an application that has a scheduled service in it and has MVC for user to click some stuff.
#Cacheable(value = "applicationToken")
public Optional<String> getToken() {
return settingsRepository.getToken();
}
#CacheEvict(value = "applicationToken", allEntries = true)
public void evictApplicationTokenCache() {
log.info("Evicting token cache.");
}
public void updateToken(String token) {
log.info("Updating token.");
settingsRepository.updateToken(token);
evictApplicationTokenCache();
}
The method getToken() is called inside the scheduled service and when I tried some test to evict cache from there it worked.
However, on the MVC side, if the user updates the token, the method updateToken() gets called and although it goes inside the evictApplicationTokenCache(), on the next retrieval of the token, I still get the same token and it doesn't step into the method getToken() to actually grab the token from the repository.
The only relation I found is that the threads are different for the MVN call and for the Scheduled call. From what I know, the cache should live on the context level, not the thread level. Therefore, it shouldn't matter which thread asks for the cache to be evicted.
It seems that the updateToken() and evictApplicationTokenCache() methods are in the same class.
In that case, the #CacheEvict annotation will be ignored, because cache handling is implemented by interceptors that are only involved when you call a method from one component to a different (injected) component.
If that's the situation, you can move the evictApplicationTokenCache() method to a helper #Component, or put the #CacheEvict annotation on the updateToken() method.

Spring Boot Cache Bulk and Access Individually

Accessing the DB repeatedly for individual entities is much slower than doing a bulk select. How do I cache a the result of a bulk select into a cache, and later access it individually?
For example, I have a Employee entity:
public class Employee {
private Integer id;
}
And I have repository that can access it either with bulk select, or individually by id:
public class EmployeeRepository {
public Map<Integer, Employee> retrieveByEmployeeIds(List<Integer> ids) {
// impl
}
public Employee retrieveByEmployeeId(Integer id) {
// impl
}
}
How do I implement it so that when retrieveByEmployeeId(Integer id) is called it will check the same cache as retrieveByEmployeeIds(List<Integer> ids), and if it doesn't exist it'll make a call to the DB, and also storing that cache with the id again?
I have answered similar questions before, for example see (Spring Cache with collection of items/entities).
Essentially, you must implement a custom CacheManager and Cache, the 2 primary interfaces that form the basis of Spring's Cache Abstraction, as described here. It may even extend or delegate to an existing caching provider, but you must "decorate" the existing functionality.
The link I referred to above also contains examples.
Hope this helps give you ideas on how to handle your particular UC.

Spring caching / spring repository, evict multiple keys

I have two methods to fetch an entity with two different parameters. I also have a save method that uses one of those parameters. How can I evict the entity from the cache under both fetch keys? e.g. see below:
#Cacheable
public User getByUsername(String username);
#Cacheable
public User getByEmail(String email);
#CacheEvict(key="#entity.username")
User save(User entity);
In the above, a call to getByEmail will return stale date.
There are several options, of course, but as usual, Spring has your back.
The easiest and most simple approach is to leverage Spring's #Caching annotation on your save method, like so...
#Caching(evict = {
#CacheEvict(cacheNames = "Users", key="#user.name"),
#CacheEvict(cacheNames = "Users", key="#user.email")
})
User save(User user);
For your reference, I created an example test class demonstrating this working here.
You will notice I imitated your example above using Spring's Cache Abstraction annotations on my UserRepository. In this case, my repo is backed by Pivotal GemFire, but any data store will work. I use a ConcurrentMap as my caching provider, using Spring's ConcurrentMapCacheManager, but of course, any caching provider will do.
My test case proceeds to save a new User, ensuring that the user is stored by not yet cached. The test then proceeds to exercise the query methods (findByName, findByEmail) ensuring that the user entity is cached appropriately in each case. I then remove the entity from the underlying data store and ensure that the entity is still cached. And finally, the moment of truth, I modify the entity, re-save the entity, asserting that the entity is stored by that all entries have been "evicted" from the cache.
You could also try, as another optimization, to combine the #CachePut annotation with the 2 #CacheEvict annotations in this case, which could restore the cache based on the new, updated entity, something like...
#Caching(
evict = {
#CacheEvict(cacheNames = "Users", key="#a0.name", beforeInvocation = true),
#CacheEvict(cacheNames = "Users", key="#a0.email", beforeInvocation = true)
},
put = {
#CachePut(cacheNames = "Users", key="#result.name"),
#CachePut(cacheNames = "Users", key="#result.email")
}
)
User save(User user);
NOTE: notice the user of the beforeInvocation attribute on the #CacheEvict annotations along with the #CachePuts
However, you may prefer that the entity be lazily added to the cache based on need.
Although, you would presume the entity is being frequently accessed/used since the save method on your repo was just called, and therefore rely on your underlying data store (such as GemFire) to set additional eviction (based on overflow)/expiration (based on LRU) settings, thereby better managing your system resources (e.g. memory) while still maintaining optimal application performance.
Food for thought.
Hope this helps.

When does Grails assign an ID to an object?

A Grails 2.3.4 application is connecting to an Oracle database using the following domain class:
class Person {
String name
static mapping = {
id column: "PERSON_ID", generator: "sequence", params: [sequence: 'person_seq']
}
}
The PersonController makes a call to a method in PersonService and it makes a call to UtilService. The method in UtilService being called has some logic based on wether this Person object is new:
if (personInstance.id == null) { ... }
What I have found is that the id property of personInstance (which is passed through the method calls described above) is assigned when the UtilService is called.
The controller action calling PersonService is #Transactional, and the services do not have any transaction configuration.
So, a couple of questions:
When is id value assigned by GORM (I assumed at insert but that seems wrong)?
Is there a better way of checking if the object is new (isAttached() returns true so that's not good for me)?
EDIT: save() has not been called on the personInstance when UtilService does the id check.
The id is assigned when you call save(). For most persistence calls, Hibernate delays flushing the change until it feels it has to flush) to ensure correctness. But save() calls are treated differently. I believe the motivation is that even if we know that flush() will eventually be called, even if it's at the very end of the request, we want to retrieve the id early so it doesn't suddenly change.
Note that a service that does "not have any transaction configuration" is transactional - the only way to get a non-transactional service is to remove all #Transactional annotations (the newer Grails annotation and the older Spring annotation) and add
static transactional = false
All other services are transactional, although you can configure individual methods to be ignored ## Headin.
Turns out, I had a findBy which was flushing the session:
utilService.someMethod(Person.findByUsername(username))
It was at this point that the id was populated.
Got around it by using withNewTransaction:
def personInstance = Person.withNewSession { Person.findByUsername(username) }
utilService.someMethod(personInstance)
Which now leads me onto the next question...

Resources