Java Spring事务感知缓存不工作
我使用SpringCache抽象,使用Ehcache作为缓存提供程序。 我正在尝试将缓存操作附加到spring JPA事务,但无法这样做 即使事务失败/回滚缓存放置也会发生 配置Java Spring事务感知缓存不工作,java,spring,caching,ehcache,Java,Spring,Caching,Ehcache,我使用SpringCache抽象,使用Ehcache作为缓存提供程序。 我正在尝试将缓存操作附加到spring JPA事务,但无法这样做 即使事务失败/回滚缓存放置也会发生 配置 @Bean public EhCacheManagerFactoryBean cacheManagerUsingSpringApi() { EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManag
@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;
}
spring-cache-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>
测试用例(调用者)
测试应该成功,即spring不应该将数据放入方法employeeRepository.customUpdate中的缓存中,如果事务在该方法中回滚。
但是,即使事务失败,spring也会将数据放入缓存。
注意:奇怪的是,若缓存中已经存在条目,若事务失败,@CachePut不会更新缓存中的条目
因此,如果我用@CachePut(cacheNames=“EmployeeCache”,key=“#result.id”)
注释employeeRepository.save
,那么缓存不会在更新调用中更新
这里缺少什么?选项1:使用建议排序,
参考:
下面的声明将首先执行事务性建议,然后执行可缓存建议
<tx:annotation-driven order="0"/>
<cache:annotation-driven cache-manager="ehCacheManager" order="1"/>
@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);
}
<tx:annotation-driven order="0"/>
<cache:annotation-driven cache-manager="ehCacheManager" order="1"/>
@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);
}