数据缓存-Java Spring

重复读取相同的数据会出现优化问题,数据不会更改或很少更改,这些是各种参考书和其他信息,即 通过密钥获取数据的功能是确定性的。 在这里,大概每个人都可以理解-我们需要一个缓存! 为什么每次都需要执行数据搜索或计算?

因此,在这里我将展示如何在Java Spring中进行缓存,并且由于缓存与数据库关系最密切,因此如何使用一个特定示例在DBMS中进行缓存。

目录内容

  • 春季缓存
  • Oracle PL-SQL函数中的缓存

春季缓存


然后,一切几乎都以相同的方式进行,在Java中,他们使用各种HasMap,ConcurrentMap等。在Spring中,也有一个简单,方便,有效的解决方案。 我认为在大多数情况下,这将有助于解决问题。 因此,所需要做的就是启用缓存并注释功能。

使缓存可访问

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

缓存功能搜索数据

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

注释指示高速缓存的名称,并且还有其他参数。 它按预期工作,第一次执行代码时,通过键(在这种情况下为名称)将搜索结果放入缓存中,并且不再执行后续调用,并从缓存中检索数据。

使用缓存的“人”资源库的示例实现

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

我检查发生了什么

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

在测试中我打了两次

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

,第一次调用即搜索,第二次从缓存中获取结果。 这在控制台中可见。

图片

您可以方便地逐点优化现有功能。 如果函数具有多个参数,则可以指定用作键的参数名称。

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

有更复杂的方案来获取密钥,这在文档中。

但是,当然,问题将是如何更新缓存中的数据? 为此有两个注释。

第一个是@CachePut

具有此批注的函数将始终调用代码,并将结果放入缓存中,以便可以更新缓存。

我将向存储库添加两种方法:删除和添加Person

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

我将进行“人物”搜索,删除,添加,再次搜索,但是像以前一样,我将从缓存中获得相同的面孔,直到调用“ 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; } 

测验

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

图片

另一个注释是@CacheEvict

使您不仅可以访问缓存存储,还可以逐出。 此过程对于从缓存中删除过时或未使用的数据很有用。

默认情况下,Spring使用-Co​​ncurrentMapCache作为缓存,如果您拥有自己的出色的类来组织缓存,则可以在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; } } 

高速缓存的名称也在那里显示,可能有多个。 在xml配置中,如下所示:

春季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> 


人类
 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; } 


项目结构

图片

在这里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> 


Oracle PL-SQL函数中的缓存


好吧,最后,不忽略DBMS功能而是使用DBMS功能的用户可以在数据库级别另外或作为替代使用缓存。 例如,在Oracle中,您同样可以将常规函数优雅地转换为通过添加结果来缓存结果的函数
RESULT_CACHE

一个例子:

 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; 

更改表中的数据后,将重建缓存,您可以使用以下方法微调缓存规则
RELIES_ON(...)
用料
缓存抽象

Source: https://habr.com/ru/post/zh-CN427187/


All Articles