Sistem interaktif menggunakan banyak direktori berbeda, kamus data, ini adalah berbagai status, kode, nama, dll. Sebagai aturan, ada banyak dari mereka dan masing-masing tidak besar. Dalam struktur, mereka sering memiliki atribut umum: Kode, ID, Nama, dll. Dalam kode aplikasi ada banyak pencarian yang berbeda, perbandingan dengan Kode, dengan ID referensi. Pencarian dapat diperluas, misalnya: pencarian berdasarkan ID, berdasarkan Kode, dapatkan daftar berdasarkan kriteria, urutkan, dll ... Dan sebagai hasilnya, direktori di-cache, mengurangi seringnya akses ke database. Di sini saya ingin menunjukkan contoh bagaimana Repositori Nilai-Kunci Data Musim Semi dapat berguna untuk tujuan ini. Gagasan utamanya adalah ini: pencarian lanjutan di Key-Value Repositorie dan, jika tidak ada objek, lakukan pencarian melalui Spring Data Repositories di database dan kemudian letakkan di Key-Value Repository.

Dan di Spring ada KeyValueOperations, yang mirip dengan repositori Spring Data, tetapi beroperasi pada konsep Key-Value dan menempatkan data dalam struktur HashMap (saya
menulis tentang repositori Spring Data di sini ). Objek dapat dari jenis apa pun, yang utama adalah kunci ditentukan.
public class Status { @org.springframework.data.annotation.Id private long statusId; private String code; private String name; ....
Di sini kuncinya adalah statusId, dan jalur lengkap anotasi secara khusus ditunjukkan, di masa depan saya akan menggunakan Entitas JPA, dan ada juga Id di sana, tetapi sudah terkait dengan database.
KeyValueOperations memiliki metode yang sama seperti di repositori Data Spring
interface KeyValueOperations { <T> T insert(T objectToInsert); void update(Object objectToUpdate); void delete(Class<?> type); <T> T findById(Object id, Class<T> type); <T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type); .... .
Jadi, Anda dapat menentukan konfigurasi java KeyValueOperations untuk Spring bean
@SpringBootApplication public class DemoSpringDataApplication { @Bean public KeyValueOperations keyValueTemplate() { return new KeyValueTemplate(keyValueAdapter()); } @Bean public KeyValueAdapter keyValueAdapter() { return new MapKeyValueAdapter(ConcurrentHashMap.class); }
Kelas penyimpanan kamus terdaftar di sini - ConcurrentHashMap
Dan karena saya akan bekerja dengan kamus Entitas JPA, saya akan menghubungkan keduanya untuk proyek ini.
Ini adalah kamus "Status" dan "Kartu"
@Entity public class Status { @org.springframework.data.annotation.Id private long statusId; private String code; private String name; @Id @Column(name = "STATUS_ID") public long getStatusId() { return statusId; } .... @Entity public class Card { @org.springframework.data.annotation.Id private long cardId; private String code; private String name; @Id @Column(name = "CARD_ID") public long getCardId() { return cardId; } ...
Ini adalah entitas standar yang sesuai dengan tabel dalam database, saya menarik perhatian pada dua anotasi Id untuk setiap entitas, satu untuk JPA, yang lain untuk KeyValueOperations
Struktur kamusnya mirip, contoh dari salah satunya
create table STATUS ( status_id NUMBER not null, code VARCHAR2(20) not null, name VARCHAR2(50) not null );
Repositori Spring Data untuk mereka:
@Repository public interface CardCrudRepository extends CrudRepository<Card, Long> { } @Repository public interface StatusCrudRepository extends CrudRepository<Status, Long> { }
Dan di sini adalah contoh DictionaryProvider sendiri di mana kita menghubungkan repositori Data Spring dan KeyValueOperations
@Service public class DictionaryProvider { private static Logger logger = LoggerFactory.getLogger(DictionaryProvider.class); private Map<Class, CrudRepository> repositoryMap = new HashMap<>(); @Autowired private KeyValueOperations keyValueTemplate; @Autowired private StatusCrudRepository statusRepository; @Autowired private CardCrudRepository cardRepository; @PostConstruct public void post() { repositoryMap.put(Status.class, statusRepository); repositoryMap.put(Card.class, cardRepository); } public <T> Optional<T> dictionaryById(Class<T> clazz, long id) { Optional<T> optDictionary = keyValueTemplate.findById(id, clazz); if (optDictionary.isPresent()) { logger.info("Dictionary {} found in keyValueTemplate", optDictionary.get()); return optDictionary; } CrudRepository crudRepository = repositoryMap.get(clazz); optDictionary = crudRepository.findById(id); keyValueTemplate.insert(optDictionary.get()); logger.info("Dictionary {} insert in keyValueTemplate", optDictionary.get()); return optDictionary; } ....
Injeksi otomatis dipasang di dalamnya untuk repositori dan untuk KeyValueOperations, dan kemudian logika sederhana (di sini, tanpa memeriksa nol, dll.), Kita melihat di kamus keyValueTemplate, jika ada, maka kita kembali, kalau tidak kita mengekstrak dari database melalui crudRepository dan tempat di keyValueTemplate, dan memberikan keluar.
Tetapi jika semua ini akan terbatas hanya untuk pencarian kunci, maka mungkin tidak ada yang istimewa. Dan KeyValueOperations memiliki berbagai operasi CRUD, dan permintaan. Berikut adalah contoh pencarian di keyValueTemplate yang sama, tetapi sudah dengan Kode menggunakan permintaan KeyValueQuery.
public <T> Optional<T> dictionaryByCode(Class<T> clazz, String code) { KeyValueQuery<String> query = new KeyValueQuery<>(String.format("code == '%s'", code)); Iterable<T> iterable = keyValueTemplate.find(query, clazz); Iterator<T> iterator = iterable.iterator(); if (iterator.hasNext()) { return Optional.of(iterator.next()); } return Optional.empty(); }
Dan bisa dimengerti, jika sebelumnya saya mencari berdasarkan ID dan objek masuk ke keyValueTemplate, maka mencari dengan kode objek yang sama akan mengembalikannya dari keyValueTemplate, tidak akan ada akses ke database. Spring Expression Language digunakan untuk menggambarkan permintaan.
Contoh Uji:
Pencarian ID
private void find() { Optional<Status> status = dictionaryProvider.dictionaryById(Status.class, 1L); Assert.assertTrue(status.isPresent()); Optional<Card> card = dictionaryProvider.dictionaryById(Card.class, 100L); Assert.assertTrue(card.isPresent()); }
Cari berdasarkan Kode
private void findByCode() { Optional<Card> card = dictionaryProvider.dictionaryByCode(Card.class, "VISA"); Assert.assertTrue(card.isPresent()); }
Anda bisa mendapatkan daftar data melalui
<T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type);
Anda dapat menentukan penyortiran dalam permintaan
query.setSort(Sort.by(DESC, "name"));
Bahan:
nilai kunci pegas dataProyek Github