代码https://github.com/HiwayChe/zheng/tree/develop/zheng-test
spring cache篇//www.greatytc.com/p/b9e85a139ea0
Cache切面在事务切面前面,只有事务执行成功才往cache中缓存数据。
代码中共有4个切面,分别为获取缓存失效时间,设置缓存,切换数据源,事务。
执行顺序:CacheExpireAdvice.before->CacheInterceptor.invoke->MultiDataSourceAdvice.before->TransactionInterceptor.invode->MultiDataSourceAdvice.afterReturning->CacheExpireAdvice.afterReturning。
其中CacheInterceptor和TransactionInterceptor没有before,afterReturning之分。
afterReturning只有在方法成功后才执行,如果target中抛了异常,那么afterReturning是不会执行的。如TransactionInterceptor执行失败,CacheInterceptor是不会缓存数据的。
执行CacheTest4测试用例,日志解析如下:
@Test
public void test(){
String key = "fafaxxx";
Account account;
for(int i=0;i<2;i++){
account = this.accountService.getAccountByName(key);
try {
this.logger.info("sleeping................");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.accountService.update(key);
this.logger.info("cache evicted....");
for(int i=0;i<2;i++){
account = this.accountService.getAccountByName(key);
try {
this.logger.info("sleeping................");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
日志:
#执行CacheExpireAdvice.before方法,获取缓存失效时间
01-11 00:35:27 [main] INFO CacheExpireAdvice.before() | CacheExpireAdvice before, target method:getAccountByName
#切换数据源
01-11 00:35:27 [main] INFO DataSourceAdvice.before() | DataSourceAdvice before,target method:getAccountByName
#当前数据源是read
01-11 00:35:27 [main] INFO MultiDataSource.determineCurrentLookupKey() | current database:read
#由于是第一次执行,缓存中没有数据,这里从db中查找
01-11 00:35:27 [main] INFO AccountService.getFromDB() | =====================real querying db... fafaxxx
#清空数据源设置(到这里说明事务成功了)
01-11 00:35:27 [main] INFO DataSourceAdvice.afterReturning() | DataSourceAdvice after,target method:getAccountByName
#db中查询的结果缓存起来,有失效时间的
01-11 00:35:27 [main] INFO MyRedisCache.put() | cache with expire.....
#清空失效时间值
01-11 00:35:27 [main] INFO CacheExpireAdvice.afterReturning() | CacheExpireAdvice after, target method:getAccountByName
#代码sleeping
01-11 00:35:27 [main] INFO CacheTest4.test() | sleeping................
#第二次执行(这时缓存中有数据了),获取缓存失效值
01-11 00:35:30 [main] INFO CacheExpireAdvice.before() | CacheExpireAdvice before, target method:getAccountByName
#由于缓存中有数据了,这里直接在CacheInterceptor中返回,不再走db。清空失效值
01-11 00:35:30 [main] INFO CacheExpireAdvice.afterReturning() | CacheExpireAdvice after, target method:getAccountByName
#代码sleeping
01-11 00:35:30 [main] INFO CacheTest4.test() | sleeping................
#进入到update方法(这个方法会清空缓存)。
01-11 00:35:33 [main] INFO DataSourceAdvice.before() | DataSourceAdvice before,target method:update
#切换数据源到write
01-11 00:35:33 [main] INFO MultiDataSource.determineCurrentLookupKey() | current database:write
01-11 00:35:33 [main] INFO AccountService.update() | update or delete account from DB, evict from cache
#清空数据源设置
01-11 00:35:33 [main] INFO DataSourceAdvice.afterReturning() | DataSourceAdvice after,target method:update
01-11 00:35:33 [main] INFO CacheTest4.test() | cache evicted....
#再次读取数据,和最上面的一样了
01-11 00:35:33 [main] INFO CacheExpireAdvice.before() | CacheExpireAdvice before, target method:getAccountByName
01-11 00:35:33 [main] INFO DataSourceAdvice.before() | DataSourceAdvice before,target method:getAccountByName
01-11 00:35:33 [main] INFO MultiDataSource.determineCurrentLookupKey() | current database:read
01-11 00:35:33 [main] INFO AccountService.getFromDB() | =====================real querying db... fafaxxx
01-11 00:35:33 [main] INFO DataSourceAdvice.afterReturning() | DataSourceAdvice after,target method:getAccountByName
01-11 00:35:33 [main] INFO MyRedisCache.put() | cache with expire.....
01-11 00:35:33 [main] INFO CacheExpireAdvice.afterReturning() | CacheExpireAdvice after, target method:getAccountByName
01-11 00:35:33 [main] INFO CacheTest4.test() | sleeping................
01-11 00:35:36 [main] INFO CacheExpireAdvice.before() | CacheExpireAdvice before, target method:getAccountByName
01-11 00:35:36 [main] INFO CacheExpireAdvice.afterReturning() | CacheExpireAdvice after, target method:getAccountByName
01-11 00:35:36 [main] INFO CacheTest4.test() | sleeping................