There is a requirement to query the product using the product name. It requires querying the cache first, and if it cannot be found, go to the database to query; after querying from the database, add it to the cache, and continue to query again. Query cache.
You can write a conditional judgment, the pseudo code is as follows:
//先从缓存中查询 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); }
The above string of codes can also achieve the query effect, It doesn't look very complicated, but this string of code is non-reusable
and can only be used in this scenario. Assuming that there are many needs similar to the above product query in our system, then we need to write if(...)else{...}
everywhere. As a programmer, it is very uncomfortable to be unable to unify similar or repeated codes, so the code for this scenario needs to be optimized.
The problem with the above code is: The input parameters are not fixed, and the return value is not fixed either. If only the parameters are not fixed, just use generics. But the most important thing is that the query method is not fixed. For example, querying products and querying users are definitely not the same query method.
So it would be great if we could pass a method (i.e. the various query methods above) as a parameter into a unified judgment method, similar to:
/** * 这个方法的作用是:先执行method1方法,如果method1查询或执行不成功,再执行method2方法 */ public static<T> T selectCacheByTemplate(method1,method2)
want To achieve the above effect, we have to mention the new features of Java8: Functional programming
There is a package in Java: java.util.function
, all of them are interfaces, and they are all modified by the @FunctionalInterface
annotation.
Function Category
Consumer: Accept parameters, no return value
Function (function): Accepts parameters and returns a value
Operator (operation): Accepts parameters and returns the same type as the parameters The value of
Predicate (assertion): Accepts parameters and returns boolean type
##Supplier (Supply): No parameters, return value
Then let’s use Java to elegantly query the cache first and then the database!Project codeConfiguration file
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 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>Project structure Among them, CacheService queries data from the cache, and GoodsService queries data from the database SpringBootQueryApplication.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); } }
package 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 + '}'; } }
Custom functional interface:
package com.example.springbootquery.function; @FunctionalInterface public interface CacheSelector<T> { T select() throws Exception; }CacheService.java
package com.example.springbootquery.service; import com.example.springbootquery.entity.Goods; public interface CacheService { /** * 从缓存中获取商品 * * @param goodsName 商品名称 * @return goods */ Goods getGoodsByName(String goodsName) throws Exception; }
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); }
I will not connect to the database here, but simulate a returnBaseUtil.java (core class)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; } }
Because I don't care about the parameters and only need a return value, Supplier is used here.Usagepackage 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); } }
The above is the detailed content of How to use Java to query cache first and then query database. For more information, please follow other related articles on the PHP Chinese website!