代碼https://github.com/HiwayChe/zheng/tree/develop/zheng-test
spring cache篇http://www.lxweimin.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................