https://blog.csdn.net/u012240455/article/details/80844361java
註釋介紹spring
@Cacheable數據庫
@Cacheable 的做用 主要針對方法配置,可以根據方法的請求參數對其結果進行緩存緩存
@Cacheable 做用和配置方法less
參數 | 解釋 | example |
---|---|---|
value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 | 例如: @Cacheable(value=」mycache」) @Cacheable(value={」cache1」,」cache2」} |
key | 緩存的 key,能夠爲空,若是指定要按照 SpEL 表達式編寫,若是不指定,則缺省按照方法的全部參數進行組合 | @Cacheable(value=」testcache」,key=」#userName」) |
condition | 緩存的條件,能夠爲空,使用 SpEL 編寫,返回 true 或者 false,只有爲 true 才進行緩存 | @Cacheable(value=」testcache」,condition=」#userName.length()>2」) |
實例spa
@Cacheable(value=」accountCache」),這個註釋的意思是,當調用這個方法的時候,會從一個名叫 accountCache 的緩存中查詢,若是沒有,則執行實際的方法(即查詢數據庫),並將執行的結果存入緩存中,不然返回緩存中的對象。這裏的緩存中的 key 就是參數 userName,value 就是 Account 對象。「accountCache」緩存是在 spring*.xml 中定義的名稱。.net
1
2
3
4
5
6
|
@Cacheable
(value=
"accountCache"
)
// 使用了一個緩存名叫 accountCache
public
Account getAccountByName(String userName) {
// 方法內部實現不考慮緩存邏輯,直接實現業務
System.out.println(
"real query account."
+userName);
return
getFromDB(userName);
}
|
@CachePutcode
@CachePut 的做用 主要針對方法配置,可以根據方法的請求參數對其結果進行緩存,和 @Cacheable 不一樣的是,它每次都會觸發真實方法的調用xml
@CachePut 做用和配置方法htm
參數 | 解釋 | example |
---|---|---|
value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 | @CachePut(value=」my cache」) |
key | 緩存的 key,能夠爲空,若是指定要按照 SpEL 表達式編寫,若是不指定,則缺省按照方法的全部參數進行組合 | @CachePut(value=」testcache」,key=」#userName」) |
condition | 緩存的條件,能夠爲空,使用 SpEL 編寫,返回 true 或者 false,只有爲 true 才進行緩存 | @CachePut(value=」testcache」,condition=」#userName.length()>2」) |
實例
@CachePut 註釋,這個註釋能夠確保方法被執行,同時方法的返回值也被記錄到緩存中,實現緩存與數據庫的同步更新。
1
2
3
4
|
@CachePut
(value=
"accountCache"
,key=
"#account.getName()"
)
// 更新accountCache 緩存
public
Account updateAccount(Account account) {
return
updateDB(account);
}
|
@CacheEvict
@CachEvict 的做用 主要針對方法配置,可以根據必定的條件對緩存進行清空
@CacheEvict 做用和配置方法
參數 | 解釋 | example |
---|---|---|
value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 | @CacheEvict(value=」my cache」) |
key | 緩存的 key,能夠爲空,若是指定要按照 SpEL 表達式編寫,若是不指定,則缺省按照方法的全部參數進行組合 | @CacheEvict(value=」testcache」,key=」#userName」) |
condition | 緩存的條件,能夠爲空,使用 SpEL 編寫,返回 true 或者 false,只有爲 true 才進行緩存 | @CacheEvict(value=」testcache」,condition=」#userName.length()>2」) |
allEntries | 是否清空全部緩存內容,缺省爲 false,若是指定爲 true,則方法調用後將當即清空全部緩存 | @CachEvict(value=」testcache」,allEntries=true) |
beforeInvocation | 是否在方法執行前就清空,缺省爲 false,若是指定爲 true,則在方法尚未執行的時候就清空緩存,缺省狀況下,若是方法執行拋出異常,則不會清空緩存 | @CachEvict(value=」testcache」,beforeInvocation=true) |
實例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@CacheEvict
(value=
"accountCache"
,key=
"#account.getName()"
)
// 清空accountCache 緩存
public
void
updateAccount(Account account) {
updateDB(account);
}
@CacheEvict
(value=
"accountCache"
,allEntries=
true
)
// 清空accountCache 緩存
public
void
reload() {
reloadAll()
}
@Cacheable
(value=
"accountCache"
,condition=
"#userName.length() <=4"
)
// 緩存名叫 accountCache
public
Account getAccountByName(String userName) {
// 方法內部實現不考慮緩存邏輯,直接實現業務
return
getFromDB(userName);
}
|
@CacheConfig
全部的@Cacheable()裏面都有一個value=「xxx」的屬性,這顯然若是方法多了,寫起來也是挺累的,若是能夠一次性聲明完 那就省事了, 因此,有了@CacheConfig這個配置,@CacheConfig is a class-level annotation that allows to share the cache names,若是你在你的方法寫別的名字,那麼依然以方法的名字爲準。
1
2
3
4
5
6
|
@CacheConfig
(
"books"
)
public
class
BookRepositoryImpl
implements
BookRepository {
@Cacheable
public
Book findBook(ISBN isbn) {...}
}
|
條件緩存
下面提供一些經常使用的條件緩存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//@Cacheable將在執行方法以前( #result還拿不到返回值)判斷condition,若是返回true,則查緩存;
@Cacheable
(value =
"user"
, key =
"#id"
, condition =
"#id lt 10"
)
public
User conditionFindById(
final
Long id)
//@CachePut將在執行完方法後(#result就能拿到返回值了)判斷condition,若是返回true,則放入緩存;
@CachePut
(value =
"user"
, key =
"#id"
, condition =
"#result.username ne 'zhang'"
)
public
User conditionSave(
final
User user)
//@CachePut將在執行完方法後(#result就能拿到返回值了)判斷unless,若是返回false,則放入緩存;(即跟condition相反)
@CachePut
(value =
"user"
, key =
"#user.id"
, unless =
"#result.username eq 'zhang'"
)
public
User conditionSave2(
final
User user)
//@CacheEvict, beforeInvocation=false表示在方法執行以後調用(#result能拿到返回值了);且判斷condition,若是返回true,則移除緩存;
@CacheEvict
(value =
"user"
, key =
"#user.id"
, beforeInvocation =
false
, condition =
"#result.username ne 'zhang'"
)
public
User conditionDelete(
final
User user)
|
@Caching
有時候咱們可能組合多個Cache註解使用;好比用戶新增成功後,咱們要添加id–>user;username—>user;email—>user的緩存;此時就須要@Caching組合多個註解標籤了。
1
2
3
4
5
6
|
@Caching
(put = {
@CachePut
(value =
"user"
, key =
"#user.id"
),
@CachePut
(value =
"user"
, key =
"#user.username"
),
@CachePut
(value =
"user"
, key =
"#user.email"
)
})
public
User save(User user) {
|
自定義緩存註解
好比以前的那個@Caching組合,會讓方法上的註解顯得整個代碼比較亂,此時可使用自定義註解把這些註解組合到一個註解中,如:
1
2
3
4
5
6
7
8
9
10
|
@Caching
(put = {
@CachePut
(value =
"user"
, key =
"#user.id"
),
@CachePut
(value =
"user"
, key =
"#user.username"
),
@CachePut
(value =
"user"
, key =
"#user.email"
)
})
@Target
({ElementType.METHOD, ElementType.TYPE})
@Retention
(RetentionPolicy.RUNTIME)
@Inherited
public
@interface
UserSaveCache {
}
|
這樣咱們在方法上使用以下代碼便可,整個代碼顯得比較乾淨。
1
2
|
@UserSaveCache
public
User save(User user)
|
擴展
好比findByUsername時,不該該只放username–>user,應該連同id—>user和email—>user一塊兒放入;這樣下次若是按照id查找直接從緩存中就命中了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Caching
(
cacheable = {
@Cacheable
(value =
"user"
, key =
"#username"
)
},
put = {
@CachePut
(value =
"user"
, key =
"#result.id"
, condition =
"#result != null"
),
@CachePut
(value =
"user"
, key =
"#result.email"
, condition =
"#result != null"
)
}
)
public
User findByUsername(
final
String username) {
System.out.println(
"cache miss, invoke find by username, username:"
+ username);
for
(User user : users) {
if
(user.getUsername().equals(username)) {
return
user;
}
}
return
null
;
}
|
其實對於:id—>user;username—->user;email—>user;更好的方式多是:id—>user;username—>id;email—>id;保證user只存一份;如:
1
2
3
4
5
6
|
@CachePut
(value=
"cacheName"
, key=
"#user.username"
, cacheValue=
"#user.username"
)
public
void
save(User user)
@Cacheable
(value=
"cacheName"
, key=
"#user.username"
, cacheValue=
"#caches[0].get(#caches[0].get(#username).get())"
)
public
User findByUsername(String username)
|
SpEL上下文數據
Spring Cache提供了一些供咱們使用的SpEL上下文數據,下表直接摘自Spring官方文檔:
名稱 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root對象 | 當前被調用的方法名 | root.methodName |
method | root對象 | 當前被調用的方法 | root.method.name |
target | root對象 | 當前被調用的目標對象 | root.target |
targetClass | root對象 | 當前被調用的目標對象類 | root.targetClass |
args | root對象 | 當前被調用的方法的參數列表 | root.args[0] |
caches | root對象 | 當前方法調用使用的緩存列表(如@Cacheable(value={「cache1」, 「cache2」})),則有兩個cache | root.caches[0].name |
argument name | 執行上下文 | 當前被調用的方法的參數,如findById(Long id),咱們能夠經過#id拿到參數 | user.id |
result | 執行上下文 | 方法執行後的返回值(僅當方法執行以後的判斷有效,如‘unless','cache evict'的beforeInvocation=false) | result |
1
2
|
@CacheEvict
(value =
"user"
, key =
"#user.id"
, condition =
"#root.target.canCache() and #root.caches[0].get(#user.id).get().username ne #user.username"
, beforeInvocation =
true
)
public
void
conditionUpdate(User user)
|