SpringCache的事务管理与单元测试

原创
03/09 10:50
阅读数 452

项目背景

在某个项目中,使用了SpringCache redis作为缓存解决方案,jpa作为orm

在单元测试时,在执行某步操作时,需要往缓存中放入数据,之后启用断言判断对应的缓存是否存在,结果全部报缓存不存在

项目配置

springCache

 @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory, RedisSerializer serializer) {
        log.info("[缓存配置] - 注入缓存管理器");
        return RedisCacheManager.builder(factory)
                //默认缓存时间
                .cacheDefaults(
                        getRedisCacheConfigurationWithTtl(300)
                                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
                )

                .transactionAware()//注意,这里是开启了redis 事务
                //自定义缓存时间
                .withInitialCacheConfigurations(getRedisCacheConfigurationMap())
                .build();
    }


单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional //这里和下一行代表测试用例结束后自动回滚
@Rollback
@SpringBootTest
public abstract class BasicMockControllerTest {
}

缓存调用


   @CachePut(key = "#result.id")
    @Override
    public User update(User user) {
        user = userRepository.save(user);
        return user;
    }

相关源码

springCache事务管理逻辑

org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#decorateCache

    public boolean isTransactionAware() {
		return this.transactionAware;
	}

	@Override
	protected Cache decorateCache(Cache cache) {
		return (isTransactionAware() ? new TransactionAwareCacheDecorator(cache) : cache);
	}


其中this.transactionAware来自 之前配置的 transactionAware()方法,对应值为true

因此,这里会创建一个有事务管理的Cache实现


TransactionAwareCacheDecorator中,核心方法 put 中,会根据配置了事务决定逻辑

代码如下

	@Override
	public void put(final Object key, @Nullable final Object value) {
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
				@Override
				public void afterCommit() {
					TransactionAwareCacheDecorator.this.targetCache.put(key, value);
				}
			});
		}
		else {
			this.targetCache.put(key, value);
		}
	}


事务何时提交

根据测试,redis事务提交时机同jdbc事务;即jdbc事务结束,提交时,redis也一起提交,相反则一起回滚

在Spring中,redis事务总是和jdbc事务相关联。

而我在单元测试中,配置了事务回滚,因此在写缓存断言的时候,事务尚未结束,redis 还不能决定提交还是回滚,此时缓存中肯定没有数据。当测试用例结束后,事务自动回滚,redis也回滚,所以手动去redis查看时,也没有数据

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部