当前位置: 首页 > 知识库问答 >
问题:

Spring事务感知缓存不工作

养翔
2023-03-14

我使用Spring缓存抽象使用Ehache作为缓存提供程序。我试图将缓存操作附加到Spring JPA事务,但无法这样做。

即使事务失败/回滚缓存放发生。

配置,

        @Bean
    public EhCacheManagerFactoryBean cacheManagerUsingSpringApi() {
        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();

        // provide xml file for ehcache configuration/
        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("spring-cache-abs-ehcache.xml"));

        return ehCacheManagerFactoryBean;
    }

    @Bean
    public org.springframework.cache.CacheManager ehCacheCacheManager() {
        final EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager(cacheManagerUsingSpringApi().getObject());
        ehCacheCacheManager.setTransactionAware(true); // Setting  transaction aware
        return ehCacheCacheManager;
    }

springcache-abs-ehcache。xml,

    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true"
         monitoring="autodetect"
         dynamicConfig="true">

    <cache name="EmployeeCache"
           maxEntriesLocalHeap="10000"
           eternal="false"
           timeToIdleSeconds="300" timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
        <persistence strategy="localTempSwap" />
    </cache>
</ehcache>

雇员安置处,

    public interface EmployeeRepository extends JpaRepository<Employee, Long>, CustomEmployeeRepository {
    }

事务方法,

    @Repository
public class EmployeeRepositoryImpl implements CustomEmployeeRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private CacheManager cacheManager;

    // THIS METHOD SHOULD NOT PUT INTO CACHE WITH NEW NAME
    @Override
    @Transactional
    @Cacheable(cacheNames = "EmployeeCache", key = "#a0.id")
    public Employee customUpdate(Employee employee) {
        employee.setFirstName(UUID.randomUUID().toString());
        entityManager.merge(employee);

        // rolling back transaction 
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

        return employee;
    }
}

测试用例(调用者),

    @Test
public void testCustomUpdate() {
    // GIVEN
    Employee employee = new Employee();
    employee.setFirstName(UUID.randomUUID().toString());
    employee.setLastName(UUID.randomUUID().toString());
    final Employee savedEmployee = employeeRepository.save(employee);

    // WHEN
    final Employee updatedEmployee = employeeRepository.customUpdate(savedEmployee);

    // THEN
    final Cache employeeCache = cacheManager.getCache("EmployeeCache");
    final Cache.ValueWrapper object = employeeCache.get(updatedEmployee.getId());
    assertNull(object);
}

测试应该成功,也就是说,如果事务在该方法中回滚,Spring不应该将数据放入方法雇员Repository.custom更新中的缓存中。但是,即使事务失败,Spring也会将数据放入缓存。注意:奇怪的部分是,如果条目已经存在于缓存中,那么@CachePUT不会在事务失败时更新缓存中的条目。

所以,如果我注释雇员Repository.save@CachePUT(cacheNames="雇员缓存",key="#result.id")然后缓存不更新更新调用。

这里少了什么?

共有1个答案

姬飞昂
2023-03-14

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-订购

下面的声明将首先执行事务性建议,然后执行可缓存建议。

<tx:annotation-driven order="0"/>

<cache:annotation-driven cache-manager="ehCacheManager" order="1"/>

如果从另一个用@Transactional注释的方法调用@Cacheable注释的方法,您将看到代码正在工作。同一方法上的@Cacheable和@Transaction这两个注释都不会对您的原因有所帮助,除非您实现了建议排序。请看下面一个粗略的逻辑实现。

    @Override
    @Transactional
    public Employee customUpdate(Employee employee) {
        Employee mergedEmployee = updateHelper(employee);

        // rolling back transaction 
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

        return mergedEmployee;
    }

    @Cacheable(cacheNames = "EmployeeCache", key = "#a0.id")
    public Employee updateHelper(Employee employee)) {
        employee.setFirstName(UUID.randomUUID().toString());
        //On a merge(...) call on the entityManager, the returned item is the managed 
        //instance
        return entityManager.merge(employee); 
    }


 类似资料:
  • 嗨,我正在尝试开发带有事务的spring和hibernate应用程序,我正在使用Spring4。x和hibernate 4。下面是我的代码片段 应用程序上下文。xml servlet上下文。xml 坚持。xml finnaly meservice看起来像这样 和 这里会发生运行时异常,但db记录没有回滚。

  • 我正在探索Ignite事务性缓存。我已经有了一段代码,它对JDBC使用Spring事务管理。我想使用Spring缓存抽象在代码中集成ignite事务性缓存。 我遇到了SpringTransactionManager(由Ignite提供),但我无法找到正确的使用方法。本质上,我想做一些类似的事情: 当事务提交时,数据库和缓存应该一起提交。为此,Ignite文档提到了使用SpringTransacti

  • 我是一个新的Spring和学习的事务概念。无法使@Transactional工作。 用例: 当getEmployee()抛出RuntimeException时,员工和员工详细信息的数据插入应该回滚。但回滚没有发生。我使用的是Oracle数据库11g和spring 4.3.1版本。下面是正在运行的独立java代码。

  • 我使用的是grails 1.3.7,代码如下: Grails服务: 我的例外: } 当代码抛出MyException时,我发现以下错误:事务回滚,因为它已被标记为仅回滚 注:如果我更改static transactional=true,则不会发生错误。 知道吗?

  • 我将Spring 3.2.4与JavaFX结合使用,并希望实现一种方法,其中操作将在事务中执行。我在控制器中的代码如下所示: 以及我的应用程序上下文: 尝试运行时,我收到以下错误消息: 该方法存在。删除注释,或者将方法从public更改为private,或者从配置中删除bean,程序就会运行,但事务注释根本不起作用。删除代理目标会导致另一个错误。

  • 我想将主数据缓存到Redis。 所以,我写了这些代码。 和 和ymlfile 但是,缓存不工作... 无论何时调用printTest方法,都将执行“getTest”方法。Redis没有数据。。。我的代码中有什么问题? SpringBoot版本是1.4.0 依赖关系是