Lewati ke konten utama

Cari di CooLWJ

选择搜索范围,输入关键词后按回车。

Bahasa

Pengantar penggunaan Spring Cache

Satu Solusi cache berbasis SpringCache

1.1 Pengantar SpringCache

springcache dirilis pada versi spring3.1. Fitur ini membungkus dan mengabstraksikan penggunaan cache, sehingga hasil cache dapat diperoleh cukup dengan menggunakan anotasi pada metode. Justru karena menggunakan anotasi, fitur ini mengatasi keterikatan antara kode bisnis dan kode cache, sehingga kode yang sudah ada dapat langsung mendukung cache tanpa menyusup ke dalam kode bisnis. Dengan demikian, pengembang dapat menggunakan cache tanpa perlu menangani detailnya.

1.2 Gambaran umum SpringCache

Ada banyak kerangka kerja cache, masing-masing dengan keunggulannya sendiri, seperti Redis, Memcached, Guava, Caffeine, dan sebagainya.
Jika program kita ingin menggunakan cache, program tersebut harus terikat dengan kerangka kerja ini. Arsitek yang cermat sudah menggunakan antarmuka untuk mengurangi keterikatan, memanfaatkan abstraksi dan polimorfisme dalam pemrograman berorientasi objek untuk memisahkan kode bisnis dari kerangka kerja tertentu.
Namun, kita tetap perlu secara eksplisit memanggil antarmuka dan metode terkait cache dalam kode, memasukkan data ke cache pada saat yang tepat, serta membaca data dari cache pada saat yang tepat. Coba pikirkan「AOP」skenario penerapannya, bukankah ini memang secara alami merupakan tugas yang seharusnya ditangani AOP?
Sejak Spring 3.1, tersedia dukungan Cache berbasis anotasi yang serupa dengan transaksi beranotasi [@Transactional](/Transactional ), serta abstraksi Cache. Sebelumnya, hal ini umumnya diterapkan melalui AOP.
Manfaat menggunakan Spring Cache:

  • Menyediakan abstraksi Cache dasar, sehingga memudahkan pergantian berbagai implementasi Cache yang mendasarinya;

  • Melalui anotasi Cache, logika cache dapat diterapkan secara transparan pada kode bisnis kita, serupa dengan transaksi, dan hanya memerlukan sedikit kode;

  • Menyediakan pembatalan perubahan cache secara otomatis saat transaksi dibatalkan;

  • Mendukung logika cache yang cukup kompleks;

Identitas teknis Spring Cache

1.3 Desain inti Spring Cache

Mulai Spring 3.1, diperkenalkan Spring Cache, yaitu abstraksi cache Spring. Dengan mendefinisikan org.springframework.cache.Cache dan org.springframework.cache.CacheManager antarmuka untuk menyeragamkan berbagai teknologi cache, serta mendukung penggunaan anotasi JCache untuk menyederhanakan proses pengembangan.
Antarmuka Cache mendefinisikan spesifikasi komponen cache, yang mencakup kumpulan berbagai operasi cache. Spring menyediakan berbagai xxxCache implementasinya: RedisCache , EhCacheCache , ConcurrentMapCache dan sebagainya.
Mengenal antarmuka Cache melalui sebagian kode sumber dan CacheManager antarmuka.

Antarmuka Cache

public interface Cache {     //Cache名称     String getName();      //Cache负责缓存的对象     Object getNativeCache();      /**      * 获取key对应的ValueWrapper      * 没有对应的key,则返回null      * key对应的value是null,则返回null对应的ValueWrapper      */     @Nullable     Cache.ValueWrapper get(Object key);      //返回key对应type类型的value     @Nullable     <T> T get(Object key, @Nullable Class<T> type);      //返回key对应的value,没有则缓存Callable::call,并返回     @Nullable     <T> T get(Object key, Callable<T> valueLoader);      //缓存目标key-value(替换旧值),不保证实时性     void put(Object key, @Nullable Object value);      //插入缓存,并返回该key对应的value;先调用get,不存在则用put实现     @Nullable     default Cache.ValueWrapper putIfAbsent(Object key, @Nullable Object value) {         Cache.ValueWrapper existingValue = this.get(key);         if (existingValue == null) {             this.put(key, value);         }          return existingValue;     }      //删除缓存,不保证实时性     void evict(Object key);      //立即删除缓存:返回false表示剔除前不存在制定key活不确定是否存在;返回true,表示该key之前存在     default boolean evictIfPresent(Object key) {         this.evict(key);         return false;     }      //清除所有缓存,不保证实时性     void clear();      //立即清楚所有缓存,返回false表示清除前没有缓存或不能确定是否有;返回true表示清除前有缓存     default boolean invalidate() {         this.clear();         return false;     }      public static class ValueRetrievalException extends RuntimeException {         @Nullable         private final Object key;          public ValueRetrievalException(@Nullable Object key, Callable<?> loader, Throwable ex) {             super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex);             this.key = key;         }          @Nullable         public Object getKey() {             return this.key;         }     }      //缓存值的一个包装器接口,实现类为SimpleValueWrapper     @FunctionalInterface     public interface ValueWrapper {         @Nullable         Object get();     } }

Terlihat bahwa antarmuka Cache mengabstraksikan operasi terkait cache seperti get put evict.

Kelas abstrak AbstractValueAdaptingCache

public abstract class AbstractValueAdaptingCache implements Cache {      //是否允许Null值     private final boolean allowNullValues;      protected AbstractValueAdaptingCache(boolean allowNullValues) {         this.allowNullValues = allowNullValues;     }      public final boolean isAllowNullValues() {         return this.allowNullValues;     }      @Nullable     public ValueWrapper get(Object key) {         return this.toValueWrapper(this.lookup(key));     }      @Nullable     public <T> T get(Object key, @Nullable Class<T> type) {         //查询到的缓存值做fromStoreValue转换         Object value = this.fromStoreValue(this.lookup(key));         //转换后非null值且无法转换为type类型则抛出异常         if (value != null && type != null && !type.isInstance(value)) {             throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value);         } else {             return value;         }     }      //从缓存中获取key对应的value,子类实现     @Nullable     protected abstract Object lookup(Object key);      //对于从缓存中获取的值,允许为空且值为NullValue时,处理为null     @Nullable     protected Object fromStoreValue(@Nullable Object storeValue) {         return this.allowNullValues && storeValue == NullValue.INSTANCE ? null : storeValue;     }      //对于要插入缓存的null值,在允许null值的情况下处理为NullValue;否则抛出异常IllegalArgumentException     protected Object toStoreValue(@Nullable Object userValue) {         if (userValue == null) {             if (this.allowNullValues) {                 return NullValue.INSTANCE;             } else {                 throw new IllegalArgumentException("Cache '" + this.getName() + "' is configured to not allow null values but null was provided");             }         } else {             return userValue;         }     }      //get操作依据,查询到缓存值非null,则fromStoreValue转换后包装成SimpleValueWrapper返回     @Nullable     protected ValueWrapper toValueWrapper(@Nullable Object storeValue) {         return storeValue != null ? new SimpleValueWrapper(this.fromStoreValue(storeValue)) : null;     } }

Kelas abstrak AbstractValueAdaptingCache Mengimplementasikan antarmuka Cache, terutama dengan mengabstraksikan logika penanganan nilai NULL.

  • allowNullValues properti ini menunjukkan apakah cache diizinkan menangani nilai NULL

  • fromStoreValue metode untuk menangani nilai NULL get operasi, pada properti allowNullValues ketika bernilai true,memperlakukan NullValue sebagai NULL

  • toStoreValue metode untuk menangani nilai NULL put operasi, pada properti allowNullValues Jika bernilai true, NULL diperlakukan sebagai NullValue, jika tidak, pengecualian akan dilemparkan

  • toValueWrapper metode menyediakan Cache di dalam antarmuka get implementasi bawaan metode, membaca nilai dari cache, lalu melalui fromStoreValue dikonversi, lalu akhirnya dibungkus menjadi SimpleValueWrapper Kembali

  • ValueWrapper get(Object key) dan T get(Object key, @Nullable Classtype) metode diimplementasikan berdasarkan metode di atas

  • ValueWrapper get(Object key) dan @Nullable Classtype) metode diimplementasikan berdasarkan metode di atas

  • lookup Metode abstrak digunakan agar subkelas dapat memperoleh nilai cache yang sebenarnya

ConcurrentMapCache

public class ConcurrentMapCache extends AbstractValueAdaptingCache {     private final String name;     //定义ConcurrentMap缓存     private final ConcurrentMap<Object, Object> store;     //如果要缓存的是值对象的copy,则由此序列化代理类处理     @Nullable     private final SerializationDelegate serialization;      public ConcurrentMapCache(String name) {         this(name, new ConcurrentHashMap(256), true);     }      //默认允许处理null     public ConcurrentMapCache(String name, boolean allowNullValues) {         this(name, new ConcurrentHashMap(256), allowNullValues);     }      //默认serialization = null     public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) {         this(name, store, allowNullValues, (SerializationDelegate)null);     }      protected ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues, @Nullable SerializationDelegate serialization) {         super(allowNullValues);         Assert.notNull(name, "Name must not be null");         Assert.notNull(store, "Store must not be null");         this.name = name;         this.store = store;         this.serialization = serialization;     }      //serialization不为空,缓存值对象的copy     public final boolean isStoreByValue() {         return this.serialization != null;     }      public final String getName() {         return this.name;     }      public final ConcurrentMap<Object, Object> getNativeCache() {         return this.store;     }      //实现lookup:store#get     @Nullable     protected Object lookup(Object key) {         return this.store.get(key);     }      //基于ConcurrentMap::computeIfAbsent方法实现;get和put的值由fromStoreValue和toStoreValue处理Null     @Nullable     public <T> T get(Object key, Callable<T> valueLoader) {         return this.fromStoreValue(this.store.computeIfAbsent(key, (k) -> {             try {                 return this.toStoreValue(valueLoader.call());             } catch (Throwable var5) {                 throw new ValueRetrievalException(key, valueLoader, var5);             }         }));     }      public void put(Object key, @Nullable Object value) {         this.store.put(key, this.toStoreValue(value));     }      @Nullable     public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {         Object existing = this.store.putIfAbsent(key, this.toStoreValue(value));         return this.toValueWrapper(existing);     }      public void evict(Object key) {         this.store.remove(key);     }      public boolean evictIfPresent(Object key) {         return this.store.remove(key) != null;     }      public void clear() {         this.store.clear();     }      public boolean invalidate() {         boolean notEmpty = !this.store.isEmpty();         this.store.clear();         return notEmpty;     }      protected Object toStoreValue(@Nullable Object userValue) {         Object storeValue = super.toStoreValue(userValue);         if (this.serialization != null) {             try {                 return this.serialization.serializeToByteArray(storeValue);             } catch (Throwable var4) {                 throw new IllegalArgumentException("Failed to serialize cache value '" + userValue + "'. Does it implement Serializable?", var4);             }         } else {             return storeValue;         }     }      protected Object fromStoreValue(@Nullable Object storeValue) {         if (storeValue != null && this.serialization != null) {             try {                 return super.fromStoreValue(this.serialization.deserializeFromByteArray((byte[])((byte[])storeValue)));             } catch (Throwable var3) {                 throw new IllegalArgumentException("Failed to deserialize cache value '" + storeValue + "'", var3);             }         } else {             return super.fromStoreValue(storeValue);         }     } }

ConcurrentMapCache mewarisi kelas abstrak AbstractValueAdaptingCache ,merupakan implementasi cache bawaan Spring。Implementasi ini mendukung penyimpanan salinan objek ke cache,dengan SerializationDelegate serialization menangani serialisasi,nilai bawaannya null yang berarti cache berbasis referensi。Operasi terkait cache didasarkan pada kelas dasar AbstractValueAdaptingCache untuk penanganan nilai null, secara bawaan mengizinkan null.

CacheManager

public interface CacheManager {     @Nullable     //获取指定name的Cache,可能延迟创建     Cache getCache(String name);      //获取当前CacheManager下的Cache name集合     Collection<String> getCacheNames(); }

CacheManager Mengelola sekumpulan Cache berdasarkan name. Tentu saja, CacheManager juga memiliki banyak kelas implementasi, seperti ConcurrentMapCacheManager 、 AbstractCacheManager dan SimpleCacheManager ,semua ini xxxCacheManager Kelas-kelas tersebut digunakan untuk menetapkan aturan pengelolaan Cache, sehingga tidak akan dibahas lebih jauh di sini.

Dua Menggunakan SpringCache

2.1 Cara menggunakan

Spring Cache adalah kerangka kerja semacam ini. Dengan memanfaatkan AOP, kerangka ini menyediakan fungsi cache berbasis anotasi dan abstraksi yang masuk akal. Kode bisnis tidak perlu memikirkan kerangka cache apa yang digunakan di lapisan bawah;cukup tambahkan sebuah anotasi untuk menerapkan fungsi cache。

Tambahkan dependensi

<!--springboot的cache支持--> <dependency>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-cache</artifactId> </dependency>  <!--配置拓展还需添加的依赖--> <dependency>   <groupId>com.github.ben-manes.caffeine</groupId>   <artifactId>caffeine</artifactId>   <version>2.9.2</version> </dependency>

Mengonfigurasi Cache

Tambahkan anotasi @EnableCaching pada kelas startup Application

@SpringBootApplication     @MapperScan("com.xxxx.dao")     @EnableCaching     public class AxxxxApplication {          public static void main(String[] args) {             SpringApplication.run(AxxxxApplication.class, args);         }      }

Mengonfigurasi jenis cache, dengan pembahasan utama di sini mengenai cache lokal

//方式一:ConcurrentMapCache (不好设置过期时间) @Configuration public class SpringCachingConfig {        @Bean      public CacheManager cacheManager() {           SimpleCacheManager cacheManager = new SimpleCacheManager();           Set<ConcurrentMapCache> mapCaches=new HashSet<>();           //配置cache类型与目录           mapCaches.add(new ConcurrentMapCache("cacheNames1"));           mapCaches.add(new ConcurrentMapCache("cacheNames2"));           mapCaches.add(new ConcurrentMapCache("cacheNames3"));           mapCaches.add(new ConcurrentMapCache("cacheNames4"));           cacheManager.setCaches(mapCaches);           cacheManager.afterPropertiesSet();           return cacheManager;      }   }     //方式二:CaffeineCache (可设置过期时间) @Configuration public class SpringCachingConfig {        @Bean     public CacheManager cacheManager() {         SimpleCacheManager cacheManager = new SimpleCacheManager();           List<CaffeineCache> caffeineCaches = new ArrayList<>();           //SysConstants.CACHE_NAMES=new ArrayList(         //Arrays.asList("cacheNames1","cacheNames2","cacheNames3","cacheNames4")         //);         for (String  cacheName: SysConstants.CACHE_NAMES) {             caffeineCaches.add(new CaffeineCache(cacheName,                     Caffeine.newBuilder()                             .initialCapacity(50)                             .maximumSize(30000)//最大存储数量                             .expireAfterWrite(2, TimeUnit.HOURS)//过期时间2 小时                             .build()));         }         cacheManager.setCaches(caffeineCaches);         return cacheManager;     }   }     //方式三。。。。还可以配置redis以及其他的方式,这里主要介绍以上两种方式

Menerapkan cache antarmuka

//控制器1 @RestController @RequestMapping("/path1") @Cacheable(cacheNames = "cacheNames1" ,key="#root.methodName+#a0" ) public class Controller1 {   }   //控制器2 @RestController @RequestMapping("/path2") @Cacheable(cacheNames = "cacheNames2" ,key="#root.methodName+#a0" ) public class Controller2 {   }   //控制器3 @RestController @RequestMapping("/path3") @Cacheable(cacheNames = "cacheNames3" ,key="#root.methodName+#a0" ) public class Controller3 {   }   //控制器4 @RestController @RequestMapping("/path4") @Cacheable(cacheNames = "cacheNames4" ,key="#root.methodName+#a0" ) public class Controller4 {   }

2.2 Penjelasan terperinci tentang anotasi SpringCache

Anotasi @Cacheable

Jika tidak ada dalam cache:kueri basis data, simpan ke cache, kembalikan hasil,
Jika ada dalam cache:langsung kembalikan hasil

Parameter Penjelasan contoh
value Nama cache, didefinisikan dalam berkas konfigurasi spring , setidaknya satu harus ditentukan Misalnya:
@Cacheable(value=”mycache”)
@Cacheable(value={”cache1”,”cache2”}
key key cache, boleh kosong, jika ditentukan harus ditulis menggunakan ekspresi SpEL, jika tidak ditentukan, secara bawaan dibuat dari gabungan seluruh parameter metode @Cacheable(value=”testcache”,key=”#userName”)
condition Kondisi penyimpanan dalam cache, boleh kosong, ditulis menggunakan SpEL, mengembalikan true atau false, penyimpanan dalam cache hanya dilakukan jika hasilnya true @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

Fungsi:Dapat digunakan untuk menulis ke cache, menyimpan hasil di dalamnya agar pemanggilan berikutnya dapat langsung mengembalikan nilai dari cache tanpa perlu mengeksekusi metode yang sebenarnya lagi. Cara penggunaan paling sederhana, nama anotasi=nama cache, contoh penggunaannya sebagai berikut:

@Cacheable(value="accountCache")// 使用了一个缓存名叫 accountCache  public Account getAccountByName(String userName) {    // 方法内部实现不考虑缓存逻辑,直接实现业务    System.out.println("real query account."+userName);     return getFromDB(userName);  }

Anotasi @CacheEvict

@CacheEvict:anotasi untuk menghapus cache, sangat berguna untuk menghapus data lama dan data yang tidak lagi diperlukan. Di sini juga ada parameter tambahan (allEntries), yang ketika diatur menjadi allEntries=true memungkinkan penghapusan seluruh entri secara massal

Parameter Penjelasan contoh
value Nama cache, didefinisikan dalam berkas konfigurasi spring , setidaknya satu harus ditentukan @CacheEvict(value=”my cache”)
key key cache, boleh kosong, jika ditentukan harus ditulis menggunakan ekspresi SpEL, jika tidak ditentukan, secara bawaan dibuat dari gabungan seluruh parameter metode @CacheEvict(value=”testcache”,key=”#userName”)
condition Kondisi penyimpanan dalam cache, boleh kosong, ditulis menggunakan SpEL, mengembalikan true atau false, penyimpanan dalam cache hanya dilakukan jika hasilnya true @CacheEvict(value=”testcache”,condition=”#userName.length()>2”)
allEntries Apakah seluruh isi cache akan dikosongkan, nilai bawaannya adalah false, jika ditetapkan menjadi true, seluruh cache akan langsung dikosongkan setelah pemanggilan metode @CachEvict(value=”testcache”,allEntries=true)
beforeInvocation Apakah pengosongan dilakukan sebelum metode dijalankan, nilai bawaannya adalah false. Jika ditetapkan menjadi true, cache akan dikosongkan sebelum metode dijalankan. Secara bawaan, jika eksekusi metode melempar pengecualian, cache tidak akan dikosongkan @CachEvict(value=”testcache”,beforeInvocation=true)

 

@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);  }

Anotasi @CachePut

@CachePut:Anotasi ini dapat digunakan ketika perlu memperbarui cache tanpa mengganggu eksekusi metode。Artinya,metode tersebut selalu dijalankan,dan hasilnya dimasukkan ke cache;

Parameter Penjelasan contoh
value Nama cache, didefinisikan dalam berkas konfigurasi spring , setidaknya satu harus ditentukan @CachePut(value=”my cache”)
key key cache, boleh kosong, jika ditentukan harus ditulis menggunakan ekspresi SpEL, jika tidak ditentukan, secara bawaan dibuat dari gabungan seluruh parameter metode @CachePut(value=”testcache”,key=”#userName”)
condition Kondisi penyimpanan dalam cache, boleh kosong, ditulis menggunakan SpEL, mengembalikan true atau false, penyimpanan dalam cache hanya dilakukan jika hasilnya true @CachePut(value=”testcache”,condition=”#userName.length()>2”)

Anotasi @CachePut memastikan metode dijalankan, sekaligus menyimpan nilai kembalian metode ke dalam cache, sehingga cache dan basis data diperbarui secara sinkron.

@CachePut(value="accountCache",key="#account.getName()")// 更新accountCache 缓存 public Account updateAccount(Account account) {    return updateDB(account);  }

Anotasi @Caching

Saat menggunakan cache, pembaruan dan penghapusan mungkin dilakukan bersamaan, sehingga beberapa anotasi digunakan sekaligus. Sedangkan @Caching dapat mewujudkan

//添加user缓存的同时,移除userPage的缓存 @Caching(     put =@CachePut(value = "user",key ="#userVo.id"), evict = @CacheEvict(value = "userPage",allEntries = true) )
@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) {

@CacheConfig

Semua @Cacheable()memiliki atribut value=“xxx”, yang jelas cukup melelahkan untuk ditulis ketika jumlah metodenya banyak. Jika semuanya dapat dideklarasikan sekaligus, tentu akan lebih praktis, sehingga muncullah konfigurasi @CacheConfig ini. @CacheConfig adalah anotasi tingkat kelas yang memungkinkan berbagi nama cache. Jika Anda menuliskan nama lain pada metode, nama yang ditetapkan pada metode itulah yang tetap berlaku.

@CacheConfig("books") public class BookRepositoryImpl implements BookRepository {    @Cacheable   public Book findBook(ISBN isbn) {...} }

Caching bersyarat
Berikut beberapa konfigurasi cache bersyarat yang umum digunakan

//@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)

Anotasi cache khusus

Misalnya, kombinasi @Caching sebelumnya membuat anotasi pada metode menyebabkan keseluruhan kode tampak cukup berantakan. Dalam keadaan ini, anotasi khusus dapat digunakan untuk menggabungkan anotasi-anotasi tersebut menjadi satu anotasi, seperti:

@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 { }

Dengan demikian, kita cukup menggunakan kode berikut pada metode, sehingga keseluruhan kode terlihat cukup rapi.

@UserSaveCache public User save(User user)

Pengembangan
Misalnya saat menjalankan findByUsername, jangan hanya memasukkan username–>user, tetapi masukkan juga id—>user dan email—>user secara bersamaan;dengan begitu, pencarian berdasarkan id berikutnya akan langsung menemukan data di cache

@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; }

Sebenarnya, untuk: id—>user;username—->user;email—>user;cara yang lebih baik mungkin adalah: id—>user;username—>id;email—>id;memastikan user hanya disimpan satu salinan;misalnya:

@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)

Data konteks SpEL
Spring Cache menyediakan sejumlah data konteks SpEL yang dapat kita gunakan. Tabel berikut diambil langsung dari dokumentasi resmi Spring:

Nama Lokasi Deskripsi Contoh
methodName objek root Nama metode yang sedang dipanggil root.methodName
method objek root Metode yang sedang dipanggil root.method.name
target objek root Objek target yang sedang dipanggil root.target
targetClass objek root Kelas objek target yang sedang dipanggil root.targetClass
args objek root Daftar parameter metode yang sedang dipanggil root.args[0]
caches objek root Daftar cache yang digunakan oleh pemanggilan metode saat ini(misalnya @Cacheable(value={“cache1”, “cache2”})),berarti ada dua cache root.caches[0].name
nama argumen Konteks eksekusi Parameter metode yang sedang dipanggil, misalnya findById(Long id), parameternya dapat kita ambil melalui #id user.id
result Konteks eksekusi Nilai kembalian setelah metode dijalankan(hanya berlaku untuk kondisi yang dievaluasi setelah metode dijalankan, seperti ‘unless', atau beforeInvocation=false pada 'cache evict') result
@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)

Ringkasan

Untuk deklarasi cache, fasilitas cache spring menyediakan sekumpulan anotasi java:
· @Cacheable
o Fungsi:memicu penulisan cache; jika data tidak ada di cache, kueri basis data, simpan ke cache, lalu kembalikan hasilnya; jika sudah ada di cache, langsung kembalikan hasilnya
o Penerapan:Mengueri basis data Metode
· @CacheEvict
o Fungsi:memicu pembersihan cache
o Penerapan:Menghapus atau mengubah basis data Metode
· @CachePut
o Fungsi:menulis ke cache(tidak memengaruhi jalannya metode).
o Penerapan:Tambahkan ke basis data Metode
· @Penyimpanan dalam cache
o Fungsi:menggabungkan kembali beberapa operasi cache yang akan diterapkan pada metode
o Penerapan:penggunaan gabungan anotasi di atas


Komentar

Mengirim

Pilih tema favorit

Tema pilihan berlaku di seluruh situs.