Every CacheBox provider — whether it's the built-in CacheBoxProvider, a LuceeProvider, a BoxLangProvider, or your own custom implementation — shares the same core, cache-agnostic API defined by the ICacheProvider interface. This means you can swap out the underlying caching engine without changing a single line of your application code.
This page covers the essential methods you will use day to day: get(), set(), and most importantly, getOrSet().
You always start by asking the CacheFactory for a named cache (or just grab the default one):
// The default cache
cache = cacheBox.getDefaultCache();
// Or a specific named cache
cache = cacheBox.getCache( "myCache" );The most basic operations are get() and set():
// Store an object for 20 minutes, with a 10 minute idle (last access) timeout
cache.set( "myKey", myComplexObject, 20, 10 );
// Retrieve it
myComplexObject = cache.get( "myKey" );If the key does not exist or has expired, get() returns an empty/null result. That means the typical caching pattern looks like this:
data = cache.get( "myKey" );
if ( isNull( data ) ) {
// produce the data
data = myService.getExpensiveData();
// cache it
cache.set( "myKey", data );
}That pattern is so common that CacheBox gives you a single method that does it all for you, atomically: getOrSet().
{% hint style="success" %}
getOrSet() is the single most useful method on any cache provider. It collapses the classic "check cache, if missing produce and store" pattern into one thread-safe call.
{% endhint %}
any function getOrSet(
required any objectKey,
required any produce,
any timeout = "",
any lastAccessTimeout = "",
any extra = {}
)| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
objectKey |
any | true | The cache key to look up (and store to, if missing) | |
produce |
any | true | A closure/UDF (no arguments) that is invoked only if the key is not found in the cache. Its return value is cached and returned | |
timeout |
any | false | "" |
The timeout to use when storing the produced object (provider specific, usually minutes) |
lastAccessTimeout |
any | false | "" |
The idle/last-access timeout to use when storing the produced object (provider specific) |
extra |
any | false | {} |
A struct of extra name-value pairs passed through to the provider's set() operation |
- CacheBox first checks if
objectKeyalready exists in the cache. If it does, that value is returned immediately — yourproduceclosure is never called. - If it does not exist, CacheBox acquires an exclusive lock scoped to that specific cache + key (so concurrent requests for the same missing key don't all stampede your data source at once).
- Inside the lock, it double-checks the cache (in case another thread just produced it while you were waiting for the lock).
- If it's still missing, it executes your
produceclosure, takes the result, stores it viaset()using thetimeout/lastAccessTimeout/extrayou provided, and returns it.
This effectively gives you cache stampede protection for free.
{% tabs %} {% tab title="BoxLang" %}
cache = cacheBox.getDefaultCache()
// Get the object from cache, or produce, cache and return it if missing
data = cache.getOrSet( "topSellingProducts", () => {
return productService.getTopSellers()
}, 30, 15 ){% endtab %} {% tab title="CFML" %}
cache = cacheBox.getDefaultCache();
// Get the object from cache, or produce, cache and return it if missing
data = cache.getOrSet( "topSellingProducts", () => {
return productService.getTopSellers();
}, 30, 15 );
{% endtab %} {% endtabs %}
You can also pass extra provider-specific arguments via the extra struct:
{% tabs %} {% tab title="BoxLang" %}
data = cache.getOrSet(
objectKey = "topSellingProducts",
produce = () => productService.getTopSellers(),
timeout = 30,
lastAccessTimeout = 15,
extra = { "priority" : "high" }
){% endtab %} {% tab title="CFML" %}
data = cache.getOrSet(
objectKey = "topSellingProducts",
produce = () => productService.getTopSellers(),
timeout = 30,
lastAccessTimeout = 15,
extra = { "priority" : "high" }
);
{% endtab %} {% endtabs %}
{% hint style="info" %}
getOrSet() is implemented once in AbstractCacheBoxProvider and inherited (or delegated to via super.getOrSet()) by every shipped provider — CacheBoxProvider, CFProvider, LuceeProvider, and BoxLangProvider — so it behaves consistently no matter which caching engine you are using.
{% endhint %}
For the full list of methods available on every provider (lookup(), clear(), clearAll(), bulk/multi operations, metadata retrieval, and more) see the ICacheProvider reference.