Caching Data - Java Spring

Berkali-kali membaca data yang sama, muncul pertanyaan tentang optimasi, data tidak berubah atau jarang berubah, ini adalah berbagai buku referensi dan informasi lainnya, yaitu fungsi memperoleh data dengan kunci adalah deterministik. Di sini, mungkin semua orang mengerti - kita perlu cache! Mengapa Anda perlu melakukan pencarian atau perhitungan data setiap saat?

Jadi di sini saya akan menunjukkan cara membuat cache di Java Spring, dan karena itu terkait erat kemungkinan besar dengan Database, lalu bagaimana melakukannya di DBMS menggunakan satu contoh spesifik.

Isi

  • Cache di Musim Semi
  • Tembolok dalam fungsi Oracle PL-SQL

Cache di Musim Semi


Kemudian semuanya datang dengan cara yang hampir sama, di Jawa mereka menggunakan berbagai HasMap, ConcurrentMap, dll. Di Spring, juga ada solusi untuk ini, sederhana, mudah, efisien. Saya pikir dalam kebanyakan kasus ini akan membantu dalam menyelesaikan masalah. Jadi, yang diperlukan hanyalah mengaktifkan cache dan membuat anotasi fungsinya.

Membuat cache dapat diakses

@SpringBootApplication @EnableCaching public class DemoCacheAbleApplication { public static void main(String[] args) { SpringApplication.run(DemoCacheAbleApplication.class, args); } } 

Data pencarian fungsi cache

  @Cacheable(cacheNames="person") public Person findCacheByName(String name) { //... } 

Anotasi menunjukkan nama cache dan ada parameter lainnya. Ini berfungsi seperti yang diharapkan, pertama kali kode dieksekusi, hasil pencarian dimasukkan ke dalam cache oleh kunci (dalam hal ini nama) dan panggilan selanjutnya tidak lagi dieksekusi, dan data diambil dari cache.

Contoh implementasi dari repositori β€œOrang” menggunakan cache

 @Component public class PersonRepository { private static final Logger logger = LoggerFactory.getLogger(PersonRepository.class); private List<Person> persons = new ArrayList<>(); public void initPersons(List<Person> persons) { this.persons.addAll(persons); } private Person findByName(String name) { Person person = persons.stream() .filter(p -> p.getName().equals(name)) .findFirst() .orElse(null); return person; } @Cacheable(cacheNames="person") public Person findCacheByName(String name) { logger.info("find person ... " + name); final Person person = findByName(name); return person; } } 

Saya memeriksa apa yang terjadi

 @RunWith(SpringRunner.class) @SpringBootTest public class DemoCacheAbleApplicationTests { private static final Logger logger = LoggerFactory.getLogger(DemoCacheAbleApplicationTests.class); @Autowired private PersonRepository personRepository; @Before public void before() { personRepository.initPersons(Arrays.asList(new Person("", 22), new Person("", 34), new Person("", 41))); } private Person findCacheByName(String name) { logger.info("begin find " + name); final Person person = personRepository.findCacheByName(name); logger.info("find result = " + person.toString()); return person; } @Test public void findByName() { findCacheByName(""); findCacheByName(""); } } 

Dalam tes saya menelepon dua kali

 @Test public void findByName() { findCacheByName(""); findCacheByName(""); } 

, pertama kali panggilan, pencarian, kedua kalinya hasilnya diambil dari cache. Ini terlihat di konsol.

gambar

Dengan mudah, Anda dapat mengoptimalkan fungsionalitas yang ada secara langsung. Jika fungsi memiliki lebih dari satu argumen, maka Anda dapat menentukan nama parameter, yang digunakan sebagai kunci.

  @Cacheable(cacheNames="person", key="#name") public Person findByKeyField(String name, Integer age) { 

Ada skema yang lebih kompleks untuk mendapatkan kunci, ini ada dalam dokumentasi.

Tapi tentu saja pertanyaannya adalah bagaimana cara memperbarui data dalam cache? Ada dua penjelasan untuk tujuan ini.

Yang pertama adalah @CachePut

Fungsi dengan anotasi ini akan selalu memanggil kode, dan memasukkan hasilnya dalam cache, sehingga dapat memperbarui cache.

Saya akan menambahkan dua metode ke repositori: hapus dan tambahkan Orang

  public boolean delete(String name) { final Person person = findByName(name); return persons.remove(person); } public boolean add(Person person) { return persons.add(person); } 

Saya akan melakukan pencarian Orang, menghapus, menambahkan, mencari lagi, tetapi seperti sebelumnya, saya akan mendapatkan wajah yang sama dari cache sampai saya memanggil "findByNameAndPut"

  @CachePut(cacheNames="person") public Person findByNameAndPut(String name) { logger.info("findByName and put person ... " + name); final Person person = findByName(name); logger.info("put in cache person " + person); return person; } 

Tes

  @Test public void findCacheByNameAndPut() { Person person = findCacheByName(""); logger.info("delete " + person); personRepository.delete(""); findCacheByName(""); logger.info("add new person"); person = new Person("", 35); personRepository.add(person); findCacheByName(""); logger.info("put new"); personRepository.findByNameAndPut(""); findCacheByName(""); } 

gambar

Anotasi lain adalah @CacheEvict

Memungkinkan Anda untuk tidak hanya mengunjungi penyimpanan cache, tetapi juga untuk mengusir. Proses ini berguna untuk menghapus data yang usang atau tidak terpakai dari cache.

Secara default, Spring menggunakan - ConcurrentMapCache untuk cache, jika Anda memiliki kelas yang sangat baik untuk mengatur cache, Anda dapat menentukannya di CacheManager

 @SpringBootApplication @EnableCaching public class DemoCacheAbleApplication { public static void main(String[] args) { SpringApplication.run(DemoCacheAbleApplication.class, args); } @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Arrays.asList( new ConcurrentMapCache("person"), new ConcurrentMapCache("addresses"))); return cacheManager; } } 

Nama-nama cache juga ditunjukkan di sana, mungkin ada beberapa. Dalam konfigurasi xml, ini ditunjukkan seperti ini:

Spring configuration.xml
 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <cache:annotation-driven/> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="person"/> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="addresses"/> </set> </property> </bean> </beans> 


Kelas pribadi
 public class Person { private String name; private Integer age; public Person(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } @Override public String toString() { return name + ":" + age; } 


Struktur proyek

gambar

Di sini pom.xml
 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demoCacheAble</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>DemoCacheAble</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 


Tembolok dalam fungsi Oracle PL-SQL


Yah, pada akhirnya, mereka yang tidak mengabaikan kekuatan DBMS, tetapi menggunakannya, dapat menggunakan caching di tingkat basis data, sebagai tambahan atau sebagai alternatif. Sebagai contoh, di Oracle, Anda dapat mengubah fungsi reguler menjadi fungsi dengan menyimpan hasil dengan menambahkannya
RESULT_CACHE

Contoh:

 CREATE OR REPLACE FUNCTION GET_COUNTRY_NAME(P_CODE IN VARCHAR2) RETURN VARCHAR2 RESULT_CACHE IS CODE_RESULT VARCHAR2(50); BEGIN SELECT COUNTRY_NAME INTO CODE_RESULT FROM COUNTRIES WHERE COUNTRY_ID = P_CODE; --    dbms_lock.sleep (1); RETURN(CODE_RESULT); END; 

Setelah mengubah data dalam tabel, cache akan dibangun kembali, Anda dapat menyempurnakan aturan cache menggunakan
RELIES_ON (...)
Material
Abstraksi cache

Source: https://habr.com/ru/post/id427187/


All Articles