Skip to content

Changes in cache made within transaction must be visible for current transaction [SPR-12756] #17353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Feb 25, 2015 · 6 comments
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process

Comments

@spring-projects-issues
Copy link
Collaborator

Stas Volsky opened SPR-12756 and commented

As TransactionAwareCacheDecorator do actual cache operations on afterCommit phase there is incorrect behavior. Changes made in transaction are not visible to that transaction.

case:

  1. begin transaction
  2. call some method annotated with @Cacheable.
  3. call another method annotated with @CacheEvict
  4. call @Cacheable method one more time

expected behavior is that on step 4 cache will be empty inside current transaction and method will be executed one more time. but as changes will be applied only on transaction commit there are still cached results.

I suggest to make ThreadLocal map inside TransactionAwareCacheDecorator that will hold uncommited changes so it will be available to current transaction only. Or may be there is another solution.


1 votes, 5 watchers

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I'm afraid this is not what TransactionAwareCacheDecorator is about: It's really just about simple after-commit callbacks.

Keeping track of transactional changes within the cache data structure is really up to the cache provider itself and requires actual transaction support in the underlying cache provider. This usually means setting up the cache provider with JTA, making it aware of transactional boundaries and letting it manage a transaction log for changes to its data structure.

We might be able to provide a variant of this under simplified conditions, so I'm keeping this issue open for any concrete proposals towards that.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Stas Volsky commented

So there is no correct way to call @CacheEvict method and than call @Cacheable method inside one transaction using current TransactionAware cache behavior and local transactions? And If we using JTA we can't set AbstractTransactionSupportingCacheManager.transactionAware=true?

Simplified conditions as I can see is to hold uncommited data and clear flag. Cache operations improvements:

  • on clear we set flag and clear uncommited data
  • on evict we set null to uncommited data
  • on put we put to uncommited data
  • on get we first trying to use uncommited data then if clear flag was set returning null (this will trigger method execution and then put) if not - using cache (can also put it to uncommited to achive some isolation)
  • on any changes to uncommited and flag data we put after complete synchronisation on transaction that will do clean

Question is where is the suitable place to do this?

@spring-projects-issues
Copy link
Collaborator Author

Stéphane Nicoll commented

Keeping a cache consistent with the current transaction is a job on its own and Spring Framework is not meant to provide such infrastructure for similar reasons that we don't implement JTA or a cache store. If you absolutely need a transactional cache there are several options around but you should be aware of the limitations that this does imply; Terracotta actually sums it up pretty well IMO.

@spring-projects-issues
Copy link
Collaborator Author

Tom Leccese commented

Juergen,

You may consider a proxy similar to the TransactionMapWrapper class in the commons transaction project.

I have used TransactionMapWrapper inside our home-grown caching (in-memory map-based) framework to provide transacting capabilities to our caches. This transaction project is dormant but the logic inside of TransactionMapWrapper has worked fine for our purposes.

In our caching framework a cache (delegating to TransactionMapWrapper) starts a transaction when a put or delete operation is invoked and the thread is currently in a transaction. When a cache transaction is started a transaction synchronization is registered with TransactionSynchronizationManager. Any puts and deletes are cached in memory (managed by the TransactionMapWrapper proxy) and are only visible to the current thread for the duration of the transaction. When the transaction commits the sync callback will write the puts and deletes to the underlying cache on commit, or discard the puts and deletes on rollback.

I suppose a developer could put a similar proxy inside of a custom implementation of CacheManager and Cache, but it would be nice if the Spring framework could provide this capability out of the box.

Thanks,
Tom Leccese

@spring-projects-issues spring-projects-issues added status: waiting-for-triage An issue we've not yet triaged or decided on type: enhancement A general enhancement in: core Issues in core modules (aop, beans, core, context, expression) and removed type: enhancement A general enhancement labels Jan 11, 2019
@rstoyanchev rstoyanchev added status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jan 11, 2019
@spring-projects-issues
Copy link
Collaborator Author

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

@ethlo
Copy link

ethlo commented Aug 2, 2019

(I apologize up-front if this is not acceptable to post)

This issue bit us, and the new solution may not be perfect, but if anyone is still interested, I started a little project here: https://github.com/ethlo/spring-tx-cache-decorator

Please feel free to post issues and PRs if something is missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process
Projects
None yet
Development

No branches or pull requests

3 participants