How do I decide which CacheConcurrencyStrategy
to use?
NonstrictReadWriteCache
,
ReadOnlyCache
,
ReadWriteCache
,
TransactionalCache
.
I read https://www.hibernate.org/hib_docs/v3/api/org/hibernate/cache/CacheConcurrencyStrategy.html, but doesn't explain in detail enough.
The Hibernate documentation does a pretty good job at defining them:
19.2.2. Strategy: read only
If your application needs to read, but
not modify, instances of a persistent
class, a read-only cache can be used.
This is the simplest and optimal
performing strategy. It is even safe
for use in a cluster.
19.2.3. Strategy: read/write
If the application needs to update
data, a read-write cache might be
appropriate. This cache strategy
should never be used if serializable
transaction isolation level is
required. If the cache is used in a
JTA environment, you must specify the
property
hibernate.transaction.manager_lookup_class
and naming a strategy for obtaining
the JTA TransactionManager
. In other
environments, you should ensure that
the transaction is completed when
Session.close()
or
Session.disconnect()
is called. If you
want to use this strategy in a
cluster, you should ensure that the
underlying cache implementation
supports locking. The built-in cache
providers do not support locking.
19.2.4. Strategy: nonstrict read/write
If the application only occasionally
needs to update data (i.e. if it is
extremely unlikely that two
transactions would try to update the
same item simultaneously), and strict
transaction isolation is not required,
a nonstrict-read-write cache might be
appropriate. If the cache is used in a
JTA environment, you must specify
hibernate.transaction.manager_lookup_class
.
In other environments, you should
ensure that the transaction is
completed when Session.close()
or
Session.disconnect()
is called.
19.2.5. Strategy: transactional
The transactional cache strategy
provides support for fully
transactional cache providers such as
JBoss TreeCache. Such a cache can only
be used in a JTA environment and you
must specify
hibernate.transaction.manager_lookup_class
.
In other words:
Read-only: Useful for data that is read frequently but never updated (e.g. referential data like Countries). It is simple. It has the best performances of all (obviously).
Read/write: Desirable if your data needs to be updated. But it doesn't provide a SERIALIZABLE isolation level, phantom reads can occur (you may see at the end of a transaction something that wasn't there at the start). It has more overhead than read-only.
Nonstrict read/write: Alternatively, if it's unlikely two separate transaction threads could update the same object, you may use the nonstrict–read–write strategy. It has less overhead than read-write. This one is useful for data that are rarely updated.
Transactional: If you need a fully transactional cache. Only suitable in a JTA environment.
So, choosing the right strategy depends on the fact that data are being updated or not, the frequency of updates and the isolation level required. If you don't know how to answer these questions for the data you want to put in cache, maybe ask some support from a DBA.
READ_ONLY: Used only for entities that never change (exception is thrown if an attempt to update such an entity is made). It is very simple and performant. Very suitable for some static reference data that don’t change.
NONSTRICT_READ_WRITE: Cache is updated after a transaction that changed the affected data has been committed. Thus, strong consistency is not guaranteed and there is a small time window in which stale data may be obtained from cache. This kind of strategy is suitable for use cases that can tolerate eventual consistency.
READ_WRITE: This strategy guarantees strong consistency which it achieves by using ‘soft’ locks: When a cached entity is updated, a soft lock is stored in the cache for that entity as well, which is released after the transaction is committed. All concurrent transactions that access soft-locked entries will fetch the corresponding data directly from database.
TRANSACTIONAL: Cache changes are done in distributed XA transactions. A change in a cached entity is either committed or rolled back in both database and cache in the same XA transaction.
Reading API Docs is good thing, but you should also read the documentation (its awesome) also, Second Level Cache - Strategies.
Transactional − Use this strategy for read-mostly data where it is critical to prevent stale data in concurrent transactions, in the rare case of an update.
Read-write − Again use this strategy for read-mostly data where it is critical to prevent stale data in concurrent transactions, in the rare case of an update.
Nonstrict-read-write − This strategy makes no guarantee of consistency between the cache and the database. Use this strategy if data hardly ever changes and a small likelihood of stale data is not of critical concern.
Read-only − A concurrency strategy suitable for data, which never changes. Use it for reference data only.
Hope this clears your doubt!