제품명을 사용하여 제품을 조회해야 한다는 요구사항이 있는데, 이를 위해서는 먼저 캐시를 조회해야 하며, 찾을 수 없는 경우 데이터베이스로 조회하여 조회한 후 캐시에 추가하세요. , 다시 쿼리할 때 먼저 캐시를 계속 쿼리합니다.
조건부 판단을 작성할 수 있습니다. 의사 코드는 다음과 같습니다.
//先从缓存中查询 String goodsInfoStr = redis.get(goodsName); if(StringUtils.isBlank(goodsInfoStr)){ //如果缓存中查询为空,则去数据库中查询 Goods goods = goodsMapper.queryByName(goodsName); //将查询到的数据存入缓存 goodsName.set(goodsName,JSONObject.toJSONString(goods)); //返回商品数据 return goods; }else{ //将查询到的str转换为对象并返回 return JSON.parseObject(goodsInfoStr, Goods.class); }
위의 코드 문자열도 쿼리 효과를 얻을 수 있지만 이 코드 문자열은 다음과 같습니다. 는 재사용할 수 없습니다.
는 이 시나리오에서만 사용할 수 있습니다. 우리 시스템에 위의 제품 쿼리와 유사한 요구 사항이 많다고 가정하면 if(...)else{...}
를 모든 곳에 작성해야 합니다. 프로그래머로서 유사하거나 반복되는 코드를 통합할 수 없다는 점은 매우 불편하므로 이 시나리오에 맞게 코드를 최적화해야 합니다. 不可复用的
,只能用在这个场景。假设在我们的系统中还有很多类似上面商品查询的需求,那么我们需要到处写这样的if(...)else{...}
。作为一个程序员,不能把类似的或者重复的代码统一起来是一件很难受的事情,所以需要对这种场景的代码进行优化。
上面这串代码的问题在于:入参不固定、返回值也不固定,如果仅仅是参数不固定,使用泛型即可。但最关键的是查询方法也是不固定的,比如查询商品和查询用户肯定不是一个查询方法吧。
所以如果我们可以把一个方法(即上面的各种查询方法)也能当做一个参数传入一个统一的判断方法就好了,类似于:
/** * 这个方法的作用是:先执行method1方法,如果method1查询或执行不成功,再执行method2方法 */ public static<T> T selectCacheByTemplate(method1,method2)
想要实现上面的这种效果,就不得不提到Java8的新特性:函数式编程
在Java中有一个package:java.util.function
,里面全部是接口,并且都被@FunctionalInterface
위 코드의 문제점은 다음과 같습니다. 입력 매개변수가 고정되어 있지 않고 반환 값도 고정되어 있지 않습니다. 매개변수만 고정되어 있지 않으면 제네릭을 사용하세요. 그러나 가장 중요한 것은 쿼리 방법이 고정되어 있지 않다는 것입니다. 예를 들어 제품 쿼리와 사용자 쿼리는 확실히 동일한 쿼리 방법이 아닙니다.
따라서 메소드(예: 위의 다양한 쿼리 메소드)를 다음과 유사한 통일된 판단 메소드에 매개변수로 전달할 수 있다면 좋을 것입니다.<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>SpringBoot-query</artifactId> <version>0.0.1-SNAPSHOT</version> <name>SpringBoot-query</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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>
함수형 프로그래밍
원리 소개
java.util.function
은 모두 인터페이스이며 다음과 같습니다. 모두 @FunctionalInterface
주석으로 수정되었습니다. 함수 분류
소비자(소비):
매개변수 허용, 반환 값 없음함수(함수):
매개변수 허용, 반환 값 있음Operator( 운영자): 매개변수를 허용하고 매개변수와 동일한 유형의 값을 반환합니다.
구체적인 내용은 다루지 않겠습니다. Java 함수형 프로그래밍 개요
코드 구현을 참조하세요. 그런 다음 Java의 우아한 구현을 사용하여 먼저 캐시를 쿼리한 다음 데이터베이스를 쿼리해 보겠습니다!
프로젝트 코드
package com.example.springbootquery; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootQueryApplication { public static void main(String[] args) { SpringApplication.run(SpringBootQueryApplication.class, args); } }
프로젝트 구조
CacheService가 캐시의 데이터를 쿼리하는 경우 GoodsService는 데이터베이스의 데이터를 쿼리합니다.SpringBootQueryApplication.javapackage com.example.springbootquery.entity; public class Goods { private String goodsName; private Integer goodsTotal; private Double price; public String getGoodsName() { return goodsName; } public void setGoodsName(String goodsName) { this.goodsName = goodsName; } public Integer getGoodsTotal() { return goodsTotal; } public void setGoodsTotal(Integer goodsTotal) { this.goodsTotal = goodsTotal; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } @Override public String toString() { return "Goods{" + "goodsName='" + goodsName + '\'' + ", goodsTotal='" + goodsTotal + '\'' + ", price=" + price + '}'; } }
사용자 정의 기능 인터페이스:
package com.example.springbootquery.function; @FunctionalInterface public interface CacheSelector<T> { T select() throws Exception; }
GoodsService.javapackage com.example.springbootquery.service; import com.example.springbootquery.entity.Goods; public interface CacheService { /** * 从缓存中获取商品 * * @param goodsName 商品名称 * @return goods */ Goods getGoodsByName(String goodsName) throws Exception; }로그인 후 복사CacheServiceImpl.java
package com.example.springbootquery.service.impl; import com.alibaba.fastjson.JSON; import com.example.springbootquery.entity.Goods; import com.example.springbootquery.service.CacheService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service("cacheService") public class CacheServiceImpl implements CacheService { @Autowired private StringRedisTemplate redisTemplate; @Override public Goods getGoodsByName(String goodsName) throws Exception { String s = redisTemplate.opsForValue().get(goodsName); return null == s ? null : JSON.parseObject(s, Goods.class); } }로그인 후 복사
package com.example.springbootquery.service; import com.example.springbootquery.entity.Goods; public interface GoodsService { Goods getGoodsByName(String goodsName); }
데이터베이스에 연결한 후에는 하지 않습니다. , 반환 시뮬레이션
package com.example.springbootquery.service.impl; import com.alibaba.fastjson.JSONObject; import com.example.springbootquery.entity.Goods; import com.example.springbootquery.service.GoodsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class GoodsServiceImpl implements GoodsService { @Autowired private StringRedisTemplate stringRedisTemplate; @Override public Goods getGoodsByName(String goodsName) { Goods goods = new Goods(); goods.setGoodsName("商品名1"); goods.setGoodsTotal(20); goods.setPrice(30.0D); stringRedisTemplate.opsForValue().set(goodsName, JSONObject.toJSONString(goods)); return goods; } }
매개변수는 신경쓰지 않기 때문에 반환 값만 필요하므로 여기서는 Supply를 사용합니다.
🎜package com.example.springbootquery.util; import com.example.springbootquery.function.CacheSelector; import java.util.function.Supplier; public class BaseUtil { /** * 缓存查询模板 * * @param cacheSelector 查询缓存的方法 * @param databaseSelector 数据库查询方法 * @return T */ public static <T> T selectCacheByTemplate(CacheSelector<T> cacheSelector, Supplier<T> databaseSelector) { try { System.out.println("query data from redis ······"); // 先查 Redis缓存 T t = cacheSelector.select(); if (t == null) { // 没有记录再查询数据库 System.err.println("redis 中没有查询到"); System.out.println("query data from database ······"); return databaseSelector.get(); } else { return t; } } catch (Exception e) { // 缓存查询出错,则去数据库查询 e.printStackTrace(); System.err.println("redis 查询出错"); System.out.println("query data from database ······"); return databaseSelector.get(); } } }
package com.example.springbootquery; import com.example.springbootquery.entity.Goods; import com.example.springbootquery.service.CacheService; import com.example.springbootquery.service.GoodsService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static com.example.springbootquery.util.BaseUtil.selectCacheByTemplate; @SpringBootTest class SpringBootQueryApplicationTests { @Autowired private CacheService cacheService; @Autowired private GoodsService userService; @Test void contextLoads() throws Exception { Goods user = selectCacheByTemplate( () -> cacheService.getGoodsByName("商品名1"), () -> userService.getGoodsByName("商品名1") ); System.out.println(user); } }
위 내용은 Java를 사용하여 캐시를 먼저 쿼리한 다음 데이터베이스를 쿼리하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!