In my app, we are using IBatis, and specifically its built in caching. Eventually I plan to use something like EhCache with IBatis, but this works for our purposes for now.
So in one of my mapping files, I had the following tag:
<cacheModel id="objCache"
type="com.ibatis.sqlmap.engine.cache.memory.MemoryCacheController"
readOnly="true" serialize="false">
</cacheModel>
I then applied this cache model to one of my result maps:
<select id="getSomething" parameterClass="..." resultMap="keyValueMap" cacheModel="objCache"> .... <select>
And I noticed an unexpected result: my query results were not actually being cached! In other words, despite the caching, the query was being executed against the database every single time.
The problem had to do with a setting on the IBatis MemoryCacheController: strong vs. weak caching. This has to do with a concept that has been there since the Java 1.3 days: weak references. Here’s one link that explains the various types of Java references:
We are used to strong references: when we have a reference to an object, the object will not be garbage collected until the reference is released. Objects referred to by weak references, on the other hand, can be reclaimed assuming there are no other references to the object .
By default, the MemoryCacheController uses weak caching by default. However, because our application only held temporary references to the cached objects (other than the cache itself), the cached objects were reclaimed by the garbage collector. Hence, the next time IBatis attempted to check the cache associated with a particular query, it did not find anything cached and ran the query again! Repeat this process, ad infinitum, and you understand why caching seemed to be nonexistent.
So I changed this:
<select id="getSomething" parameterClass="..."
resultMap="keyValueMap" cacheModel="objCache">
<property name="referenceType" value="STRONG"/>
</cacheModel>
Note I am now resetting the reference type to STRONG, which causes the cache to use strong references rather than weak references. This solved the problem, because now the reference to the cached object itself will prevent the cached object from being garbage collected.
It is interesting to note that before I solved the problem, I noticed something strange: this problem did not occur when I ran the debugger. In other words, the debugger caused the cache to work correctly! The cached objects were not being garbage collected, and thus the IBatis cache did not have to run the queries again. This is not an application of the Heisenberg uncertainty principle (in which watching a quantum phenomenon changes its progression), but actually was due to the compiler itself holding references to the cached objects, whcih caused the objects to remain cached.