Reputation: 129
I'm using latest Ehcache in my Spring 4.1.4 application. What I have is:
class Contact{
int id;
int revision;
}
@Cacheable("contacts")
public List<Contact> getContactList(List<Integer> contactIdList) {
return namedJdbc.queryForList("select * from contact where id in (:idlist)", Collections.singletonMap("idlist", contactIdList));
}
@CachePut(value="contact", key = "id")
public void updateContact(Contact toUpdate) {
jdbctemplate.update("update contact set revision = ? where id = ?", contact.getRevision(), contact.getId());
}
What I want to achieve is, that contacts are stored in the cache, and when I'm calling the getContactList
method again, that all contacts whose id
is already cached are retrieved from the cache and the other ones should be queried normally and then cached. This cache should then update the cached contact entity when it is updated.
I'm using plain Spring JDBC and Ehcache, no JPA and no Hibernate.
Upvotes: 12
Views: 7784
Reputation: 101
I believe something like this should work without customizing the existing cache manager. Main idea is to query for cached contacts prior to make a DB query and then return joined list of cached and non-cached contacts. Note:
@Cacheable
annotation on getContactList
method anymorefindContactFromCache
method is called from within getContactList
which will not work out of the box until you put it in a separate bean or use AspectJ/Self inject solutions.public List<Contact> getContactList(List<Integer> contactIdList) {
//the list below is created just to avoid original contactIdList to be modified
var idList = new ArrayList<Integer>(contactIdList);
var cachedContacts = new ArrayList<Integer>;
var contactIterator = idList.iterator();
while(contactIterator.hasNext()) {
var contactId = iterator.next();
var contact = findContactFromCache(contactId);
if(contact == null) continue;
contactIterator.remove();
cachedContacts.add(contact);
}
var nonCachedContacts = namedJdbc.queryForList("select * from contact where id in (:idlist)", Collections.singletonMap("idlist", idList));
return cachedContacts.addAll(nonCachedContacts);
}
@CachePut(value="contact", key = "id")
public void updateContact(Contact toUpdate) {
jdbctemplate.update("update contact set revision = ? where id = ?", contact.getRevision(), contact.getId());
}
@Cacheable("contact")
public Contact findContactFromCache(int id) {
return null;
}
Upvotes: 0
Reputation: 726
Worked for me. Here's a link to my answer. https://stackoverflow.com/a/60992530/2891027
TL:DR
@Cacheable(cacheNames = "test", key = "#p0")
public List<String> getTestFunction(List<String> someIds) {
more info about my enviroment in the answer.
Upvotes: 0
Reputation: 18762
Don't think that is possible. List<Integer>
will be the key against the return value of getContactList
will be saved in Cache.
So, unless the list of IDs that are being input to your getContactList
contains exactly same IDs as in one of the previous calls, it will be a cache miss and data will be fetched from DB. (NOTE: Two lists are considered equal if they exactly contain same elements and in same order)
One option is to change your method getContactList(List<Integer> contactIdList)
to getContact(Integer id)
- in this case it may take a while to build cache, but once a Contact for a given ID is in cache, DB will not be used to re-fetch it in future calls.
Though not elegant, but another option is to do the caching manually in getContactList
method.
Upvotes: 0