2015-08-11 4 views
0

Я пытаюсь настроить транзакционный ehcache, используя Spring @Cacheable и @Transactional.Ehcache локальные транзакции с Spring @Transactional

Мои кэши прекрасно работают с @Cacheable, но как только я настроить мой кэш использовать локальную транзакцию:

<cache name="currencyCodeMaps" maxElementsInMemory="100" overflowToDisk="false" timeToIdleSeconds="5" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" transactionalMode="local"/> 

Когда я получить доступ к кэш я получаю сообщение об ошибке:

net.sf.ehcache.transaction.TransactionException: transaction not started 

даже хотя тот же метод аннотируется @Transactional. Мой менеджер Весна сделка:

org.springframework.orm.jpa.JpaTransactionManager 

ehcache documentation говорит локальные транзакции контролируются явным образом:

Local transactions are not controlled by a Transaction Manager. Instead there is an explicit API where a reference is obtained to a TransactionController for the CacheManager using cacheManager.getTransactionController() and the steps in the transaction are called explicitly

Но это будет трудно, так как я хочу, чтобы синхронизировать свои Ehcache операции с БД операций, и DB транзакции контролируются @Transactional.

Есть ли способ заставить локальные транзакции Ehcache работать с Spring @Transactional?

ответ

1

Да, есть способ достичь цели.

  1. Поскольку у вас есть 2 транзакционных ресурсы (JTA и Ehcache) и не использовать JTA вы должны использовать менеджер соединения транзакций, как org.springframework.data.transaction.ChainedTransactionManager из проекта пружинных данных

    @Bean 
    public PlatformTransactionManager transactionManager() { 
        return new ChainedTransactionManager(ehcacheTransactionManager(), jpaTransactionManager()); 
    } 
    
    @Bean 
    public EhcacheTransactionManager ehcacheTransactionManager() { 
        return new EhcacheTransactionManager(ehcacheManager().getTransactionController()); 
    } 
    
    @Bean 
    public PlatformTransactionManager jpaTransactionManager() { 
        return new JpaTransactionManager(entityManagerFactory()); 
    } 
    
  2. Вы должны указать, какие менеджер транзакций должен быть использование по умолчанию:

    @Configuration 
    public class Configuration implements TransactionManagementConfigurer { 
    ... 
        @Override 
        public PlatformTransactionManager annotationDrivenTransactionManager() { 
         return transactionManager(); 
        } 
    ... 
    } 
    
  3. реализации EhcacheTransactionManager

    import net.sf.ehcache.TransactionController; 
    import net.sf.ehcache.transaction.local.LocalTransactionContext; 
    import org.springframework.transaction.TransactionDefinition; 
    import org.springframework.transaction.TransactionException; 
    import org.springframework.transaction.support.AbstractPlatformTransactionManager; 
    import org.springframework.transaction.support.DefaultTransactionStatus; 
    
        public class EhcacheTransactionManager extends AbstractPlatformTransactionManager { 
    
        private TransactionController transactionController; 
    
        public EhcacheTransactionManager(TransactionController transactionController) { 
         this.transactionController = transactionController; 
        } 
    
        @Override 
        protected Object doGetTransaction() throws TransactionException { 
         return new EhcacheTransactionObject(transactionController.getCurrentTransactionContext()); 
        } 
    
        @Override 
        protected void doBegin(Object o, TransactionDefinition transactionDefinition) throws TransactionException { 
         int timeout = transactionDefinition.getTimeout(); 
         if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { 
          transactionController.begin(timeout); 
         } else { 
          transactionController.begin(); 
         } 
        } 
    
        @Override 
        protected void doCommit(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException { 
         transactionController.commit(); 
        } 
    
        @Override 
        protected void doRollback(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException { 
         transactionController.rollback(); 
        } 
    
        public class EhcacheTransactionObject { 
    
         private LocalTransactionContext currentTransactionContext; 
    
         public EhcacheTransactionObject(LocalTransactionContext currentTransactionContext) { 
          this.currentTransactionContext = currentTransactionContext; 
         } 
    
        } 
    
    } 
    

исходный код и тестовый пример можно найти here

Это решение имеет существенный координатору недостаток транзакций Ehcache не поддерживает приостановить/возобновить операции, так внутренние операции (PROPAGATION_REQUIRES_NEW) не представляется возможным. Вот почему я должен был найти еще один.

Другой вариант - не использовать локальные транзакции ehcache вообще и использовать org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware, который украшает кеши, чтобы отложить операции до конца транзакции. Но он имеет следующие недостатки:

  1. выселили ключи оставаться доступными внутри транзакции, пока транзакция не совершат
  2. putIfAbsent операция не откладывается

Это было проблемой для меня, поэтому я реализовал эту функциональность по-разному , Проверьте 'me.qnox.springframework.cache.tx.TxAwareCacheManagerProxy ', были решены проблемы, описанные выше, в том же хранилище

0

Вы не хотите использовать локальные транзакции, вам нужны транзакции XA, которые поддерживаются Ehcache.

Посмотрите документацию на Ehcache 2.10.x или Ehcache 2.8.x.

Смежные вопросы