首页 文章

Ehcache与Spring @Transactional进行本地交易

提问于
浏览
2

我正在尝试设置事务性ehcache,使用Spring @Cacheable和@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 . 我的Spring事务管理器是:

org.springframework.orm.jpa.JpaTransactionManager

ehcache documentation表示本地交易是明确控制的:

本地事务不受事务管理器控制 . 相反,有一个显式API,使用cacheManager.getTransactionController()获取CacheManager的TransactionController的引用,并明确调用事务中的步骤

但这很难,因为我想将我的ehcache事务与数据库事务同步,而数据库事务由@Transactional控制 .

有没有办法让本地Ehcache事务与Spring @Transactional一起使用?

2 回答

  • 0

    是的,有一种方法可以实现你的目标 .

    • 因为您有2个事务资源(JTA和Ehcache)并且不使用JTA,您必须使用spring-data项目中的复合事务管理器,如 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());
    }
    
    • 您需要指定默认情况下应使用的事务管理器:
    @Configuration
    public class Configuration implements TransactionManagementConfigurer {
    ...
        @Override
        public PlatformTransactionManager annotationDrivenTransactionManager() {
            return transactionManager();
        }
    ...
    }
    
    • 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 来装饰缓存以推迟操作直到事务结束 . 但它有以下缺点:

    • 在事务提交之前,被驱逐的密钥在事务内保持可访问状态

    • putIfAbsent 操作未延期

    这对我来说是一个问题,所以我以不同的方式实现了这个功能 . 检查'me.qnox.springframework.cache.tx.TxAwareCacheManagerProxy',上面描述的问题已解决,在同一个存储库中

  • 3

    您不希望本地事务,您想要Ehcache支持的XA事务 .

    查看Ehcache 2.10.xEhcache 2.8.x的文档 .

相关问题