Daten-Caching - Java Spring

Beim wiederholten Lesen derselben Daten stellt sich die Frage der Optimierung, die Daten ändern sich nicht oder nur selten, dies sind verschiedene Nachschlagewerke und andere Informationen, d. H. Die Funktion, Daten per Schlüssel zu erhalten, ist deterministisch. Hier versteht wahrscheinlich jeder - wir brauchen einen Cache! Warum müssen Sie jedes Mal eine Datensuche oder -berechnung durchführen?

Hier werde ich zeigen, wie Cache in Java Spring erstellt wird. Da dies höchstwahrscheinlich mit der Datenbank zusammenhängt, wird dies anhand eines bestimmten Beispiels im DBMS durchgeführt.

Inhalt

  • Cache im Frühling
  • Cache in Oracle PL-SQL-Funktionen

Cache im Frühling


Dann läuft alles ungefähr gleich ab, in Java verwenden sie verschiedene HasMap, ConcurrentMap usw. Auch im Frühjahr gibt es eine Lösung dafür, einfach, bequem, effizient. Ich denke, dass dies in den meisten Fällen zur Lösung des Problems beitragen wird. Sie müssen also nur den Cache aktivieren und die Funktion mit Anmerkungen versehen.

Cache zugänglich machen

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

Suchdaten für Cache-Funktionen

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

Die Anmerkung gibt den Namen des Caches an und es gibt andere Parameter. Es funktioniert wie erwartet, wenn der Code zum ersten Mal ausgeführt wird, das Suchergebnis vom Schlüssel (in diesem Fall Name) in den Cache gestellt wird und die nachfolgenden Aufrufe nicht mehr ausgeführt werden und die Daten aus dem Cache abgerufen werden.

Eine Beispielimplementierung des Repositorys "Person" mithilfe eines Caches

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

Ich überprüfe, was passiert ist

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

Im Test rufe ich zweimal an

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

, das erste Mal ein Anruf, eine Suche, das zweite Mal, wenn das Ergebnis aus dem Cache genommen wird. Dies ist in der Konsole sichtbar.

Bild

Praktischerweise können Sie die vorhandene Funktionalität punktuell optimieren. Wenn die Funktion mehr als ein Argument enthält, können Sie den Parameternamen angeben, der als Schlüssel verwendet werden soll.

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

Es gibt komplexere Schemata zum Abrufen eines Schlüssels. Dies finden Sie in der Dokumentation.

Aber natürlich wird die Frage sein, wie Daten im Cache aktualisiert werden können. Zu diesem Zweck gibt es zwei Anmerkungen.

Der erste ist @CachePut

Eine Funktion mit dieser Annotation ruft immer den Code auf und legt das Ergebnis im Cache ab, damit der Cache aktualisiert werden kann.

Ich werde dem Repository zwei Methoden hinzufügen: Löschen und Person hinzufügen

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

Ich werde eine Personensuche durchführen, löschen, hinzufügen, erneut suchen, aber wie zuvor erhalte ich das gleiche Gesicht aus dem Cache, bis ich "findByNameAndPut" aufrufe.

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

Test

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

Bild

Eine weitere Anmerkung ist @CacheEvict

Ermöglicht es Ihnen, nicht nur den Cache-Speicher zu besuchen, sondern auch zu räumen. Dieser Vorgang ist nützlich, um veraltete oder nicht verwendete Daten aus dem Cache zu entfernen.

Standardmäßig verwendet Spring - ConcurrentMapCache für den Cache. Wenn Sie über eine eigene hervorragende Klasse zum Organisieren des Caches verfügen, können Sie diese im CacheManager angeben

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

Dort werden auch die Namen der Caches angegeben, es können mehrere vorhanden sein. In der XML-Konfiguration wird dies folgendermaßen angezeigt:

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> 


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


Projektstruktur

Bild

Hier 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> 


Cache in Oracle PL-SQL-Funktionen


Letztendlich können diejenigen, die die DBMS-Leistung nicht vernachlässigen, sondern nutzen, das Caching zusätzlich oder alternativ auf Datenbankebene verwenden. In Oracle können Sie beispielsweise eine gewöhnliche Funktion nicht weniger elegant in eine Funktion verwandeln, indem Sie das Ergebnis durch Hinzufügen zwischenspeichern
RESULT_CACHE

Ein Beispiel:

 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; 

Nachdem Sie die Daten in der Tabelle geändert haben, wird der Cache neu erstellt. Sie können die Cache-Regel mithilfe von optimieren
RELIES_ON (...)
Material
Cache-Abstraktion

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


All Articles