it-swarm.asia

Bagaimana menghindari caching ketika nilainya nol?

Saya menggunakan jambu biji untuk melakukan caching data panas. Ketika data tidak ada di cache, saya harus mendapatkannya dari database seperti ini.

public final static LoadingCache<ObjectId, User> UID2UCache = CacheBuilder.newBuilder()
        //.maximumSize(2000)
        .weakKeys()
        .weakValues()
        .expireAfterAccess(10, TimeUnit.MINUTES)
        .build(
        new CacheLoader<ObjectId, User>() {
            @Override
            public User load(ObjectId k) throws Exception {
                User u = DataLoader.datastore.find(User.class).field("_id").equal(k).get();
                return u;
            }
        });

Masalah saya adalah ketika data tidak ada dalam database juga, saya lebih suka mengembalikan nol dan tidak melakukan caching. Tapi jambu hanya menyimpan null dengan kunci di cache dan membuang pengecualian ketika saya mendapatkannya

com.google.common.cache.CacheLoader $ InvalidCacheLoadException: CacheLoader mengembalikan nol untuk shisoft kunci.

Jadi, bagaimana cara menghindari caching nilai null?

45
Shisoft

Hanya membuang beberapa Pengecualian jika pengguna tidak ditemukan dan menangkapnya dalam kode klien saat menggunakan get(key) metode. 

new CacheLoader<ObjectId, User>() {
    @Override
    public User load(ObjectId k) throws Exception {
        User u = DataLoader.datastore.find(User.class).field("_id").equal(k).get();
        if (u != null) {
             return u;
        } else {
             throw new UserNotFoundException();
        }
    }
}

Dari CacheLoader.load(K) Javadoc:

Returns:  
  the value associated with key; must not be null  
Throws:  
  Exception - if unable to load the result

Menjawab keraguan Anda tentang caching nilai null:

Mengembalikan nilai yang terkait dengan kunci dalam cache ini, memuat pertama nilai itu jika perlu. Tidak ada kondisi yang dapat diamati terkait dengan ini cache dimodifikasi hingga pemuatan selesai.

(dari LoadingCache.get(K) Javadoc)

Jika Anda melempar pengecualian, beban tidak dianggap selesai, jadi tidak ada nilai baru yang di-cache.

SUNTING:

Perhatikan bahwa dalam Kafein , yang merupakan semacam cache Guava 2.0 dan "menyediakan cache dalam memori menggunakan API yang terinspirasi Google Guava" you can return null dari metode load :

 Returns:
   the value associated with key or null if not found

Jika Anda dapat mempertimbangkan untuk bermigrasi, pemuat data Anda dapat dengan bebas kembali ketika pengguna tidak ditemukan.

67
Xaerxess

Solusi sederhana: gunakan com.google.common.base.Optional<User> alih-alih User sebagai nilai.

public final static LoadingCache<ObjectId, Optional<User>> UID2UCache = CacheBuilder.newBuilder()
        ...
        .build(
        new CacheLoader<ObjectId, Optional<User>>() {
            @Override
            public Optional<User> load(ObjectId k) throws Exception {
                return Optional.fromNullable(DataLoader.datastore.find(User.class).field("_id").equal(k).get());
            }
        });

EDIT: Saya pikir jawaban @Xaerxess lebih baik.

44

Menghadapi masalah yang sama, menyebabkan nilai-nilai yang hilang di sumber adalah bagian dari alur kerja normal. Belum menemukan sesuatu yang lebih baik daripada menulis beberapa kode sendiri menggunakan metode getIfPresent, get dan put. Lihat metode di bawah ini, di mana local adalah Cache<Object, Object>:

private <K, V> V getFromLocalCache(K key, Supplier<V> fallback) {
    @SuppressWarnings("unchecked")
    V s = (V) local.getIfPresent(key);
    if (s != null) {
        return s;
    } else {
        V value = fallback.get();
        if (value != null) {
            local.put(key, value);
        }
        return value;
    }
}
3

Ketika Anda ingin men-cache beberapa nilai NULL, Anda bisa menggunakan staf lain yang berperilaku sebagai NULL.

Dan sebelum memberikan solusinya, saya sarankan Anda untuk tidak mengekspos LoadingCache ke luar. Sebagai gantinya, Anda harus menggunakan metode untuk membatasi ruang lingkup Cache.

Misalnya, Anda bisa menggunakan LoadingCache<ObjectId, List<User>> sebagai tipe pengembalian. Dan kemudian, Anda bisa mengembalikan daftar kosong ketika Anda tidak bisa mengambil nilai dari database. Anda bisa menggunakan -1 sebagai Integer atau LongNULLvalue, Anda bisa menggunakan "" sebagai StringNULLvalue, dan sebagainya. Setelah ini, Anda harus menyediakan metode untuk menangani nilai NULL.

when(value equals NULL(-1|"")){
   return null;
}
0
jayxhj